Experience Sitecore ! | More than 200 articles about the best DXP by Martin Miles

Experience Sitecore !

More than 200 articles about the best DXP by Martin Miles

StackOverflow: Need clarity on Sitecore template values, standard values, and branch templates

One more question from a developer startin with Sitecore, who had a point of confusion between templates, standard values and branch templates (link to the original question on StackOverflow).

When creating a data template: what is the difference between just filling in the values on the template, and adding standard values? Don't both become default values whenever you create an instance of that template? If I want to make sure each item of a template has a certain value, which should I use and why? When is it appropriate to just fill out the value on the template, as opposed to adding standard values?
Branch templates: I need to create a group of items whenever a single item is created, and it sounds like branch templates are perfect for this. However, I recently read that instantiated items from a branch template stop inheriting the moment they're created.

For example, I have a branch template called Store, and create an item based off of this called Walmart. I then add features to the Store by adding new items, but Walmart doesn't get those changes? If this is problematic to my situation. I really need to keep all instantiated items in line with the branch template, and give them the new features. If my understanding is correct, how can I get around this?

I decided to answer and it seems to be a pretty good explanation:

Templates. For mature .NET developer it would make sense to think about templates as about C# classes - they define the data structure for the items that would be created on that particular template. Like classes in C# they may be inherited, but unlike in C# multiple inheritance is supported with them. Official documentation on templates is quite descriptive and handy: https://sdn.sitecore.net/upload/sitecore7/70/data_definition_api_cookbook_sc70_a4.pdf

Standard Values is a kind of blueprint prototype item for your template. You create some default values that will be auto-filled as soon as you create an item of that particular template. Standard Values item is a child item of a template definition item. You may also use tokens - dynamic values like $name, $parentname, $date, $time, $now, $id and others (you may also create your own tokens). Please read more about standard values: http://goo.gl/uUZJZf

enter image description here

Branch templates allow you to re-produce a sub-tree on instantiation, not just one item, but also some children (and children of those children) as you specify in branch template itself. As on screenshot below, whatever is selected within red frame will be created as a result of branch template instantiation:

enter image description here

Also, Sitecore items can't inherit from values set in a branch template. They will always default to the values in the original template's standard values. This is a limitation of branches (as described in this SO question: http://goo.gl/PSElYy)

As far as I understood your case, you should have a branch template called Store (somewhere underneath /sitecore/templates/Branches) and within that item reproduce exact structure that will be created on when template is used to replicate into a new branch in your content. Again, you may use tokes all around branch template (at any level) - they would be replaced with actual values. Likewise, when you use your Store branch template to create Walmart, you may auto set its display name to Walmart by using $name token.

Sitecore with SEO: overview and compare ways for managing duplicate content

In this blog post I decided to cover all ways of managing duplicate content in Sitecore and overview possible ways of dealing with that with emphasis on SEO. So, we have the following options to consider:

  1. Duplicates
  2. Clones
  3. Proxies
  4. Aliases
  5. IIS URL Rewrite module
  6. Sitecore Redirect Module
  7. External Reverse Proxy

1. Duplicates are commonly known and most straightforward way of creating duplicates (clones) of the items. The easiest way to perform that operation is to right click the item you'd want to copy, select Duplicate from context menu and specify new item's name.


This ends up with an entirely independent new item (and all its ancestors) located at the same level, including all field values, presentation details, permissions etc. Beware the locks and workflows - those also would be exact match of those original items have. After that, new item lives it own life and is no way synchronized to its original prototype (except Standard Values, for sure, as both new and duplicate items share the same template).

Also it's worth of mentioning Copy To - this brings similar behavior, but allows to create duplicates keeping same name but at other paths rather than original item. Copy To is available from the same context menu.


2. Clones are sort of similar to duplicates with the difference that no new item is created when using clones. To create a clone for a highlighted item from a Sitecore tree, select Configure tab, hit Clone and specify where you'd want to locate your clone.


Notice, that clones are displayed in content tree in a slightly light font color, I personally think that may create some future issues when business users may perform some actions on item without realizing that item is a clone. Why is that important to know? Let's view the way clones function on a lower level.

When you create a clone the item and the values are not physically copied. Instead, the inheritance similar to the one between Standard Values (that is sort of prototype item for a template) and real template item, is created (clone inherits not from s.v. but from original item). When you modify a filed value of original item, that would affect same field of cloned item. However the reverse process, when you modify a field value on cloned item, overrides that individual field value and it is no more tied to original item's field. Other fields of the same item will still keep the reference to their originals. Clones use the __Source field of the Advanced section from standard template to specify the cloned item:


Unlike duplicates, clones do not clone most of standard fields (those coming from standard template) like locks / workflows and statistics (created, updated, revision). But they do clone security settings, which, again, can be overridden for a clone item.

If you want to get rid of clone item - there are 2 ways to do that: just delete the clone (obvious) and unclone it. Uncloning turns cloned item into a normal item and copies field values from originals. Clones exist only in master database, when you perform publishing to CD servers - uncloning takes place there.

You also can do some crazy things like creating clones of clones - inheritances chain take place in this case; each field at each level can be overridden, for sure.

To get even more understanding on how clones work in Sitecore I recommend reading Cloning What Ifs article.


3. Proxies is another mechanism of creating and managing duplicate content in Sitecore. The are frequently used in cases similar when you have an item that you may want to be a child of multiple parent items. In order to use them you must ensure a config file setting called proxiesEnabled is true; then you create proxy items at /Sitecore/System/Proxies based on /System/Proxy template. However, proxies considered to be outdated in favor of Clones. Please do not use Proxies!


4. Aliases are the different beast. They are perfectly good for promos and campaigns as the normally specify a quick URL for campaign landing page. Aliases have out-of-box limitation that they are set only per root level and not multisite-friendly (however there is a link that explains how to implement that feature on your own).

Aliases are defined under /sitecore/system/Aliases based on the System/Alias template.

There is just one field in alias template that allows to select target item.

There are two more overheads when working with aliases - sometimes you may need to identify if an item is alias:

bool isAlias = Context.Database.Aliases.Exists(path);

Also you may need to set canonical URLs on them to improve SEO. Good way of doing that is:

public class AliasResolver : Sitecore.Pipelines.HttpRequest.AliasResolver
{
    public override void Process(HttpRequestArgs args)
    {
        base.Process(args);

        if (Context.Item != null)
        {
            args.Context.Items["CanonicalUrl"] = Context.Item.GetFullUrl(args.Context.Request.Url);
        }
    }
}

Also, do not forget to publish your aliases to content delivery databases, as they won't work until published.



5. IIS URL Rewrite module is probably most functional option, it is external to Sitecore, that means it happens before routing and before pipelines.

For the drawbacks of using IIS URL Rewrite I would mention that you'd need to have access to IIS Manager or web.config write permission on each of content delivery servers. I previously wrote a blog post IIS URL Rewrite module - few SEO tricks that can demonstrate how powerful it is.

Also I would beware you of some specific Sitecore URLs and create appropriate extensions (ex. for WebResource.axd - take from real code).



6. Sitecore Redirect Module is another good choice as it does perfect server side 301 redirect for both URLs and items. It is almost as powerful as IIS URL Rewrite, but because it is configured in Sitecore - you do not need to have CD environments access at all - just create and publish redirect rules (as you normally do with generic content) - they will take effect immediately! Module is transparent to multi-site configuration, it can do redirects from one site's URL or item to another.

One more advantage of the module - availability of source code, so functionality can be extended to any bespoke requirement, also it becomes compatible with new Sitecore versions by just rebuilding it with appropriate Sitecore.Kernel.dll and replacing updated module DLL in webroot bin folder.

The only drawback, probably, is that in default state it performs only 301 redirects (however you may implement whatever you require). Please remember, that 301 requests are cached by browser -so you you are testing it intensively - you may need to purge browser cache from time to time.


7. External Reverse Proxy can be another option. It can do not only rewrites to external websites, but also rewrite some requests to alternative internal URL and pass that to IIS as "given" and further down to Sitecore. I met such scenarios several times on projects I took part. By the way, did you know that IIS can also serve as reverse proxy?

Performing rewrites and URL resolving logic outside of Sitecore can be both advantageous and disadvantageous. What traps does it bring?

Well, imagine you are new developer who start working on a new working copy of source code. When you run locally you may have different URL patterns compared to those on production environment. Business users usually deal with external production URLs and do not know internal structure, so that is how they form tasks and change requests. If you are not enough lucky to have comprehensive documentation or senior colleagues who can explain how is that configured - you may end up in multiple puzzling hours of attempting to find and match URLs from different environments.

Also, SEO much relies on sitemaps, so if you are using dynamic sitemaps - you need to implement that custom URL resolving logic that you have on reverse proxy. Also Sitemap Module from the Market would not work for you in that case.


I hope this article helped you to understand you options are with their pros and cons and to pick up a proper implementation depending on exact scenario.

Best way to master Rocks - use it with Sitecore Rocks Cheat Sheet!


Recently, I came across a question on StackOverflow where a guy asked how he could edit Standard Values for a certain template using Sitecore Rocks (here is the original question with my answer). Rocks has so many features, that it is not as trivial to keep them all in one's mind. So how do I challenge that?

The document I have found (and even printed out) could not be over exaggerated and lists most of the features grouped by the way you access them just in one two-sided A4 paper.

You may download it by this link.

One more point to mention: in case you have some decent experience with Sitecore already but never used Rocks, please do give it a try. For the first moment you will not find it as convenient and the more you got used to classical Sitecore web interface - the harder you may find it to start using Rocks. But please, don't give up with that, just give Rock a bit more time and as soon as you start getting used to it - you'll start wondering how did you manage to work without it previously and why didn't you try it earlier!

StackOverflow: How to edit template content properties via sitecore rocks?

I have recently came across a question on StackOverflow I couldn't pass by. Here's original question:

Is it possible to edit content property via sitecore rocks plugin for VS ? for example Item Buckets section?


I knew that is not quite obvious so would want to share the answer:

Sure, that is possible. As I understood you right, you have an item with its fields loaded right hand side in Sitecore Rocks, you you do see custom fields but do not see fields coming from Standard Template, including Bucketable.

In that case just do right mouse click somewhere on the right hand side part, where your fields are and select Standard Fields from context menu. This will show those fields.



Hope someone might find that helpful!

original question on StackOverflow

StackOverflow: Adding route in Application_Start

One more question I could not pass by on StackOverflow (link to original question):

I am using sitecore 7.5 and I need to add new route in application_start in order to use it in ajax call but when I run the application it seems that sitecore deals with the route as content item any help please.

Below in my answer:

Here is the code that creates a route for you. In global.asax.cs you will call RegisterRoutes from App_Start event handler:

    protected void Application_Start()
    {
        RouteConfig.RegisterRoutes(RouteTable.Routes);
    }

And there you specify your route as:

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.MapRoute(
             name: "test",
             url: "mvc/Forms/{action}/{id}",
             defaults: new { controller = "Forms", action = "Test", id = UrlParameter.Optional }
           );
    }

You will have /mvc/ prefix in this case that will handle your route to specifies controller, so you will call it as:

/mvc/Forms/Test/{you_may_pass_some_optional_GUID_here}

This will route to FormsController class action method Test(string id) but you may omit id parameter

A bit of attention: Please note that setting route in Application_Start is not the best way of doing that; much better is to implement mapping routes at Initialize pipeline, as it fits Sitecore architecture:

public class Initialize
{
    public void Process(PipelineArgs args)
    {
        MapRoutes();
    }

    private void MapRoutes()
    {
        RouteTable.Routes.MapRoute(
                "Forms.Test", 
                "forms/test", 
                new
                {
                    controller = "FormsController",
                    action = "Test"
                },
                new[] { "Forms.Controller.Namespace" });
     }
}

The rest of implementation: Also I have previously wrote an article in my blog about how to implement ajax call to a route, that will guide you through the rest of the implementation process:

https://blog.martinmiles.net/post/editing-content-on-a-cd-server

Update: Please also make sure your config has a handler to handle your prefix, see below:

<customHandlers>
    <handler trigger="~/mvc/" handler="sitecore_mvc.ashx" />
Hope someone finds this helpful!


PowerShell Module issue - got a NullReferenceException when trying to open PowerShell ISE

Today I downloaded the latest (v.3.1 for Sitecore 8_001) PowerShell module and decided to play around one concept I hoped to push forward. But unfortunately, as soon as I opened ISE window, I got a NullReferenceException.


I thought that could possibly be related to my Sitecore instance. Thus I have installed a new copy of Sitecore 8.0.4 using Sitecore Instance Manager. Then tried to install package at that instance and magically worked there. So, two instances with the same Sitecore version, same PowerShell module, but different results... hm-m...

Then I assumed that ISE is trying to run some default script and probably that fact for some reason causes the exception. So, what are difference between two instances? I thought that initial ISE script might be rely on home item, and the one may be hardcoded, while my first sitecore instance has several website roots, but none of them is called Home. Worth of checking that idea. Just as the quickest, I have duplicated one of my webroots within /sitecore/content node and set a copy with the name Home. And voila - it magically worked for me!



Understanding Buckets: adding new items to buckets correctly

I just came across a question on StackOverflow about Buckets, so I decided to highlight in my blog, as it it is based on very common misunderstanding of Buckets and their functioning principles. Here's the link to original SO question.

If briefly, a guy asked why having a bucket folder with several items in it, when he tries to add a new item, the one appears in a folder as normal item, not hidden. So every time he adds new item he has to perform Sync on that. So let's go and reproduce the situation by steps.

Prerequisites: I have a folder with some items that I am turning into a bucket (at that stage we assume those Articles 1 - 5 have Bucketable checkbox being set on individual level; if you don't know how to update a checkbox for multiple already existing items - here is the great blog post about mass update field values I wrote about):


At this stage my folder is a bucket, items are not displayed, but are searchable, everything functions as normal.



The issue: Then I try to add a new item called Article 6 into my bucket folder. That item is being created as normal, is diaplyed within a folder, and there is also a notification panel warning about storing unbucketable item within a bucket folder. I believe - that is an issue of person asking a question on StackOverflow (see image below). That new item has normal path as an immediate child of bucket folder (not date-specific as defaults for bucket items path) and looking into Item Buckets sections reveals that Bucketable checkbox is not set. To add this Article 6 item into bucket, one needs to check its Bucketable field and then perform Sync from the Ribbon above.


But why that behavior happens?


Solution: Well, this checkbox isn't set but should be on items creation. How do we get that behavior? Just checking that checkbox in corresponding template's Standard Values. Screenshot below shows Article template that is a data template for all Article items. Standard Values for template are always called as __Standard Values so fields set in that item (with static values or tokens) will be auto pre-set each time and item of that template is being created:



So, as soon we have updated Standard Values with Bucketable checked, we try to create another article (of the same template, for sure), we logically call it Article 7. Once created, Article 7 is already bucketable by its Standard Values and is immediately stored in the bucket. There's no need to perform Sync! It also preloads content area right hand side (or you may search for it from Search tab) and if you pay attention to an Item path field - it is being located exactly as specified in (default in our example) bucketing configuration:



Hope this post helps you to understand a concept that is hidden behind the buckets!

Mass update of field value for all existing items of certain template - two ways of achieving result

Given: I have multiple already existing items of a specific template across my content tree. Template has some field that I want to update with a new value for all existing items, within some node I can specify.

Use cases for that scenario are really universal - you may use that for various purposes. What comes into my head, at a first glance, is the situation when you would like to assign some template to a workflow but already have multiple existing items of that template (just to remind - setting a field value at Standard Values will apply for all new, but not existing items of that particular template). In that case you need assign a workflow to each existing item individually.

Another good example is when you have a folder with multiple items, growing in amount with time flow. Then you may decide to make a folder bucketable, but those existing items require to set a Bucketable checkbox for each existing item individually. I have described that case in one of my previous blog posts - "Understanding Buckets: adding new items to buckets correctly". So let's pick up second case and try to solve it.

Solution: So, what are possible ways of achieving that goal? Not so much of them, there are just two options.

1. Straightforward option - use C# code. With C# task may be achieved by a recursive method, that accepts an item, verifies if the one is of desired template and if yes - updates the field and does the same for all item's children if any. Here is an example of such method and example of call :

private void UpdateAllFieldsRecursively(Item parentItem, string templateName, string fieldName, string newValue)
{
    if (parentItem != null)
    {
        using (new SecurityDisabler())
        {
            foreach (Item childItem in parentItem.Children)
            {
                if (childItem.Fields[fieldName] != null && childItem.TemplateName == templateName)
                {
                    using (new EditContext(childItem))
                    {
                        childItem[fieldName] = newValue;
                    }
                }

                if (childItem.HasChildren)
                {
                    UpdateAllFieldsRecursively(childItem, templateName, fieldName, newValue);
                }
            }
        }
    }
}

// and below there is the call to recursive mehod
const string parentNode = "/sitecore/content";
var database = Sitecore.Context.Database;
var parentItem = database.GetItem(parentNode);

UpdateAllFieldsRecursively(parentItem, "Article", "Bucketable", "1");

The code above works out perfectly and does exactly what we want from it, however there are certain disadvantages: first of all you need to run the code in some context - call if from some existing class, for example. Second - as that is C# code - it must be re-compiled and re-deployed. And if you may need to amend small change into the code - will have to re-compile and re-deploy again. But, luckily, there is a much better and faster alternative:

2. PowerShell Module. That module integrates into the platform and offers unprecedentedly ultimate possibilities and power over Sitecore instance and databases. After installation there is PowerShell console and more advanced PowerShell ISE, where you may create and test scripts. They are executed immediately without any of prerequisites like rebuilt DLL with a code at your bin folder. So, here is a script that does exactly the same as previous C# code:

cd 'master:/sitecore/content'
Get-ChildItem -Recurse . | Where-Object { $_.TemplateName -match "Article" -and $_.Fields["Bucketable"] -ne $null } | ForEach-Object {
   
    $_.Editing.BeginEdit()
    $_.Fields["Bucketable"].Value = "1";
    $_.Editing.EndEdit()
    ""
}

PowerShell script above does exactly the same - iterates Sitecore tree for "Article" templates, starting recursively from /sitecore/content node and if anything found - updates the filed value.

Hope this code helps!

How to host several sites within the same Sitecore instance without specifying a hostname, just on different ports

Challenge: I have got a test server running, where I usually deploy early builds and proofs of concept for business users to acknowledge. Since recent solution has grown to several websites, so I want users to be able to access all of them. The problem occurs from that users do not have administrative permissions to their PCs and are not able to edit hosts file in order to set multiple host names for my server IP (most of them also are not aware how to do that). The good news is that despite being geographically distributed and being in different virtual networks, they do have access to the server IP address.

Unfortunately, I was not able to specify multiple host names (or IP addresses) to the server as a part of infrastructure configuration, so it became obvious that users should access those websites by IP address, moreover the same IP address to all sites. So what came first into my mind was to distinguish websites by ports within same IIS. Sounds good, but how to do that? I definitely knew that the it resolves website by the host name, not the port, as set within <sites> node of config file. I tried googling a solution but did not find anything...


Investigation: Thus, armed with Reflector and dotPeek tools I started investigating and debugging original code from Sitecore.Kernel.dll. Since a while I came across SiteResolver class, that serves a processor for httpRequestBegin pipeline:


    ...

    ...

So far, so good. The method doing resolving job is called ResolveSiteContext, so I already morally prepared to inherit from SiteResolver class and override that method, implementing site resolution by port.

But what was my excitement, when I notices that it calls SiteContextFactory.GetSiteContext passing hostname, file path and port! So it already supposes port coming from config file, doesn't it? Let's go and inspect this method:

    public static SiteContext GetSiteContext(string hostName, string fullPath, int portNumber)
    {
      fullPath = fullPath.ToLowerInvariant();
      foreach (SiteInfo info in SiteContextFactory.Sites)
      {
        if (info.Matches(hostName, fullPath, portNumber))
          return new SiteContext(info);
      }
      return (SiteContext) null;
    }

and Matches() method follows as:

    public bool Matches(string host, string folder, int portNumber)
    {
      return this.MatchesHost(host) && this.MatchesPort(portNumber) && this.MatchesFolder(folder);
    }

After looking at MatchesPort(portNumber) I chased portNumber and where it comes from. It occurred that parser expects attribute with name "port" and takes the value out of it, or sets default value(0).

Right, so in fact that proves that port number can be solely used for resolving site within same Sitecore instance. But why there is lack of references or documentation about that? In any case this blog post fills the gap, I hope.


Testing: Now it's time to test my assumption. I have created two bindings for my sitecore instance, for 80 and 8080 ports. Notice that there's no hostnames assigned:

Challenge: I have got a test server running, where I usually deploy early builds and proofs of concept for business users to acknowledge. Since recent solution has grown to several websites, so I want users to be able to access all of them. The problem occurs from that users do not have administrative permissions to their PCs and are not able to edit hosts file in order to set multiple host names for my server IP (most of them also are not aware how to do that). The good news is that despite being geographically distributed and being in different virtual networks, they do have access to the server IP address.

Unfortunately, I was not able to specify multiple host names (or IP addresses) to the server as a part of infrastructure configuration, so it became obvious that users should access those websites by IP address, moreover the same IP address to all sites. So what came first into my mind was to distinguish websites by ports within same IIS. Sounds good, but how to do that? I definitely knew that the it resolves website by the host name, not the port, as set within <sites> node of config file. I tried googling a solution but did not find anything...


Investigation: Thus, armed with Reflector and dotPeek tools I started investigating and debugging original code from Sitecore.Kernel.dll. Since a while I came across SiteResolver class, that serves a processor for httpRequestBegin pipeline:


    ...

    ...

So far, so good. The method doing resolving job is called ResolveSiteContext, so I already morally prepared to inherit from SiteResolver class and override that method, implementing site resolution by port.

But what was my excitement, when I notices that it calls SiteContextFactory.GetSiteContext passing hostname, file path and port! So it already supposes port coming from config file, doesn't it? Let's go and inspect this method:

    public static SiteContext GetSiteContext(string hostName, string fullPath, int portNumber)
    {
      fullPath = fullPath.ToLowerInvariant();
      foreach (SiteInfo info in SiteContextFactory.Sites)
      {
        if (info.Matches(hostName, fullPath, portNumber))
          return new SiteContext(info);
      }
      return (SiteContext) null;
    }

and Matches() method follows as:

    public bool Matches(string host, string folder, int portNumber)
    {
      return this.MatchesHost(host) && this.MatchesPort(portNumber) && this.MatchesFolder(folder);
    }

After looking at MatchesPort(portNumber) I chased portNumber and where it comes from. It occurred that parser expects attribute with name "port" and takes the value out of it, or sets default value(0).

Right, so in fact that proves that port number can be solely used for resolving site within same Sitecore instance. But why there is lack of references or documentation about that? In any case this blog post fills the gap, I hope.


Testing: Now it's time to test my assumption. I have created two bindings for my sitecore instance, for 80 and 8080 ports. Notice that there's no hostnames assigned:



Voila! Hope this hapens to be helpful and may save some efforts for you in future!

Within Sitecore Desktop I created two website landing pages for each of sites.
Here is te content for Primary website sitting on default 80 port:

and below is the same for Secondary website on 8080:


Finally, assign them in the config file. Notice, there is no hostname defined again. Only start item and port number:


Ok, now publish both sites to web database and try accessing them. The first one (primary) opens on default port 80 by simply entering IP address. Expected behavior! It shows content exactly as configured earlier:


Just aplyint port number (8080) to the same IP address we got routed to secondary website. As expected, again:


Voila! Hope this hapens to be helpful and may save some efforts for you in future!

Web Forms for Marketers 8.0 - missing Save to Database action and making it work with SQL database again

As we know, Sitecore version 8.0 incorporated popular the module called Web Forms for Marketers (WFFM), and it became an integral part of Sitecore. WFFM is still shipped as a package, however now through Sitecore SDN portal, rather than via Marketplace as before.

So, let's assume you have a brand clean install of Sitecore (I have 8.0 Update 4 for this example). In order to download WFFM for 8.0 Update 4 please follow to https://dev.sitecore.net/Downloads/Sitecore_Experience_Platform/8_0/Sitecore_Experience_Platform_80_Update4.aspx and find download link below in the module section.

Remark 1: zip archive you download is not a package - it is normal archive containing 2 child packages - first is package for CM instance and additionally contains all dialogs etc. while another is just CD installation package. For our demonstration, unpack Web Forms for Marketers 8.0 rev. 150625.zip into /Data/Packages directory and use Development Tools - Installation Wizard, as you normally install packages.

Remark 2: ensure you have Mongo up and running, otherwise it will come to "package never installs" issue (more details about that bug here). it is required just for installation, after you have it installed you it is safe to turn off Mongo - WFFM will save data to database without any problems.

Remark 3: it may take up to 5 minutes to install the package, so please do not panic, as soon as you got Mongo running - you'll reach the point when it prompts you for setting Placeholder settings.


After WFFM installation is complete, you may configure a form. By default WFFM contains several pre-created forms as an example for people to play with it and get acknowledges with the module. For those who are new to WFFM here is a screenshot below displaying how to locate Form Designer:


Selecting Form Designer above loads a screen with the list of existing forms. Let's pick Get Our Newsletter form and click OK. Form Designer will load form configuration screen with fields and Subscribe button at the bottom. A click to that button opens Submit panel left hand side with several settings for pre-save (validation), save and post-save (success page / success message).


Remark 4: Those who used to work with previous versions of WFFM will be frustrated by missing Save to Database action from save actions menu. These are save actions that come out of box:


There is nothing to worry about, Save to Database action is still there but is not displayed only because as it always happens. However:

Remark 5: SQL database itself is not coming with the package, so you need to pick database backup from one of previous versions - its schema remains the same. To make you life easier, I have attached forms empty database backup so you may download it by this link. In WFFM 8.0 there is the setting that references connection string name (in you ConnectionStrings.config file) that is used by WFFM.

<!-- CONNECTION STRING - Sets the name of the connection string -->
<setting name="WFM.ConnectionString" value="wfm" />
<add name="wfm" connectionString="Data Source=.;Initial Catalog=test2_Forms;Integrated Security=False;User ID=sa;Password=your_password" />

To make Get Our Newsletter form work, we need to assign it to some page. Default landing page called Home will work well for our purpose. This is how you set a form to a placeholder:


Image above displays webform, because we use default layout that comes with webforms aspx page. For MVC there is rendering called Form MVC. With next step below (as clicking Edit button) you need to specify which exact form should be served by this sublayout (or rendering for MVC):



Now you may verify /Home page in Publish - Preview screen or publish web site and then load the page normally (http://your.site.name/) so you end up with something like on a screenshot below:


After you fill in valid email and click Subscribe button, you'll get "Thank you for filling in the form" message, that's in case database was references correctly. if not - there will be message abut unexpected error and corresponding exception details will appear in log file.

Let's get physically into database to verify the data has been stored correctly. In successful case you'll see one record in Form table and few records in Field table, one record per each form field.


That's all!

Following blog post will demonstrate how to make WFFM result screen display forms records from SQL database.