SharePoint: why you cannot Save Site as template

There are two reasons why you might not be able to save a site as a template. In this post I will explain what the reasons are and how you can figure out what is causing your problem. The first reasons is that the publishing feature is activated and the second reason is that custom scripts are not allowed.

1. Publishing  features activated

The most common issues is that the publishing feature is activated on the site or on a parent site. If you are trying to make a template of a subsite this will not work when the parent site has an active publishing feature.

  1. Open the site settings
  2. Click on Manage site features
  3. Check if the publishing feature is active
  4. Do this also for possible parent sites

‘Solution’ for subsite without Publishing active

I have never run into problems when using this method for subsites. However be careful it is not supported by Microsoft for a reason.

  1. Create the following URL for you specific site
  2. [SiteURL]/_layouts/savetmpl.aspx
    or
    [SiteURL]/_layouts/15/savetmpl.aspx

Truely not supported ‘solution’ when publishing is active

I don’t recommend using this so called solution, you can run into all kinds of issues. I do however want to mention this because you can find this all over the internet being claimed as an actual solution.

  1. Create the following URL for you specific site
  2. [SiteURL]/_layouts/savetmpl.aspx
    or
    [SiteURL]/_layouts/15/savetmpl.aspx

Second truely not supported ‘solution’ when publishing is active

I also don’t recommend using this so called solution, you can run into all kinds of issues. I do however also want to mention this because you can find this all over the internet being claimed as an actual solution.

  1. Open the site settings
  2. Click on Manage site features
  3. Deactivate the Publishing feature
  4. Create the following URL for you specific site
  5. [SiteURL]/_layouts/savetmpl.aspx
    or
    [SiteURL]/_layouts/15/savetmpl.aspx

2. Custom Scripts are not allowed

If publishing is not activated, it is possible that custom scripting is not allowed on the tenant level. You can see in the SharePoint Admin Center if its allowed or not. If you don’t have permission to do this you can also check it by using the following method.

  1. Open the site settings
  2. Click on Manage site features
  3. Do you see the following options? Then custom scripts are not allowed.
  4. Do you see the following options? Then custom scripts are allowed.

Solution to allow for custom scripts

  1. Open the SharePoint Admin Center in the Office 365 Admin Center

  2. Click on Settings and go to the Custom Script section.
  3. Choose “Allow users to run custom script” for Allow users to run custom script on personal sites and Allow users to run custom script on self-service created sites
  4. Click OK.
  5. It might take up to 24 hours before you can now save the site as an template.

SharePoint: Add a web part to a page layout

When customizing SharePoint we often create our own page layouts for solutions like news, events or information pages. In some cases I add a web part to the page layout. Adding web parts to a page layout when you use your own editor (not SharePoint Designer) can be a bit difficult if you don’t know all the coding details. To make live a bit more easy I use the following steps.

Solution

The solution consist of two parts creating the required web part and adding it to a page layout, three if you us another editor than SharePoint Designer.

Creating the web part

  • Add the required web part to a test page
  • Configure the web part as required
  • Export the web part to your local computer
  • Upload the web part into the web part (galery), located on the site collection settings

Page layout

  • Open SharePoint Designer and open the site collection where you uploaded the web part
  • Create a new page layout or edit an existing page layout
  • Go to the location where you want to add the web part
  • Click on Insert, then web parts and select the required web part

Another editor

  • Open the page layout in your editor
  • Copy the web part code from SharePoint Designer and paste it into your editor of choice

JavaScript / jQuery: Hide/show fields

With SharePoint we use a lot of lists and libraries to store and share information, we add and change this information with the help of forms. In most cases we create one form with all the information required for the content. Even if not all the information is required for all types of content or if it depends on a phase or status. With the help of jQuery and JavaScript we can create a more dynamic form that will hide/show fields based on selected values of fields. Make sure to disable the quick option, otherwise user will be able to edit the field outside of the provided solution.

SharePoint 2013/Online: Disable Quick edit

  1. Open the list or library settings
  2. Open the Advanced settings
  3. Set Quick Edit to No

SharePoint 2010: Disable Datasheet editing

  1. Open the list or library settings
  2. Open the Advanced settings
  3. Set Datasheet to No

JavaScript: New Form

  1. Open your favorite JavaScript Editor.
  2. Create a new JavaScript file called NewFormHideShow.js
  3. Add the following base code to the JavaScript file.

    $( document ).ready(function() {
       
    }
    );
  4. The first step is to hide the columns. Find the display names of the field that need to be hidden. Note that you need the name located in the HTML nobr tag.
  5. You can use a DOM explorer to find the correct names.
  6. For each field add the following code.
    $('nobr:contains("[Field Name]")').closest('tr').hide(); 
    
  7. In my example I hide two fields, Finalized Date and Finalized By. My example code for the document ready function is shown below.
    $(document).ready(function()
       {
          $('nobr:contains("Finalized Date")').closest('tr').hide(); 
          $('nobr:contains("Finalized By")').closest('tr').hide();
       });
    
  8. The second step is to make the function that hides or shows the fields depended on the selected value.
  9. Add the following code to the JavaScript.
    (function($){
       function showHideRegionLocation() 
       {
          var FeedbackMatchingValue = 'Final';
    
          var thisDiv = $("select[title='Status']"); 
          var mmFieldValue = thisDiv.find("option:selected").text();
    		
          $('nobr:contains("Finalized Date")').closest('tr').hide(); 
          $('nobr:contains("Finalized By")').closest('tr').hide();
    			
          if (mmFieldValue.indexOf(FeedbackMatchingValue) > -1) 
          {
             $('nobr:contains("Finalized Date")').closest('tr').show(); 
             $('nobr:contains("Finalized By")').closest('tr').show();
          } 					
       }
    
  10. Set the var FeedbackMatchingValue to the value which will show the hidden fields.
  11. Set the var thisDiv to the name of the Field that is used to show/hide the fields. Note that different types are just for different columns example Select or Input.
  12. Add the hide and Show codes. The code hides or show the table row (tr).
  13. Add the final function to the code. This part makes sure the functions runs when a users selects and/or reselects the option.
    $(document).ready(function() {
       $("select[id^='Status'").on('blur', showHideRegionLocation).on('change', showHideRegionLocation);
       });
    })(window.jQuery);
  14. Change the value after id^ to the field that contains the value on which field are being shown/hidden.
  15. The final code looks like this.
    $(document).ready(function()
       {
          $('nobr:contains("Finalized Date")').closest('tr').hide(); 
          $('nobr:contains("Finalized By")').closest('tr').hide();
    });
    
    (function($){
       function showHideRegionLocation() 
       {
       var FeedbackMatchingValue = 'Final';
       
       var thisDiv = $("select[title='Status']"); 
       var mmFieldValue = thisDiv.find("option:selected").text();
    		
       $('nobr:contains("Finalized Date")').closest('tr').hide(); 
       $('nobr:contains("Finalized By")').closest('tr').hide();
    			
       if (mmFieldValue.indexOf(FeedbackMatchingValue) > -1) 
       {
          $('nobr:contains("Finalized Date")').closest('tr').show(); 
          $('nobr:contains("Finalized By")').closest('tr').show();
       } 	
    }
    
    $(document).ready(function() {
       $("select[id^='Status'").on('blur', showHideRegionLocation).on('change', showHideRegionLocation);
       });	
    })(window.jQuery);
    

JavaScript: Edit Form

  1. The edit form is almost completely the same, only the last function is different.
  2. Open your favorite JavaScript Editor.
  3. Create a new JavaScript file called EditFormHideShow.js
  4. Follow the steps 3 – 12 from the chapter JavaScript: New Form.
  5. Add the final function to the code. This part makes sure the functions runs when a users selects and/or reselects the option.
    $(document).ready(function() {
       setTimeout(function() {
          showHideRegionLocation();
       }, 1000);
       $("select[id^='Status'").on('blur', showHideRegionLocation).on('change', showHideRegionLocation);
       });	
    })(window.jQuery);
    
  6. Change the value after id^ to the field that contains the value on which field are being shown/hidden.
  7. The final code looks like this.
    $(document).ready(function()
       {
          $('nobr:contains("Finalized Date")').closest('tr').hide(); 
          $('nobr:contains("Finalized By")').closest('tr').hide();
    });
    
    (function($){
       function showHideRegionLocation() 
       {
       var FeedbackMatchingValue = 'Final';
       
       var thisDiv = $("select[title='Status']"); 
       var mmFieldValue = thisDiv.find("option:selected").text();
    		
       $('nobr:contains("Finalized Date")').closest('tr').hide(); 
       $('nobr:contains("Finalized By")').closest('tr').hide();
    			
       if (mmFieldValue.indexOf(FeedbackMatchingValue) > -1) 
       {
          $('nobr:contains("Finalized Date")').closest('tr').show(); 
          $('nobr:contains("Finalized By")').closest('tr').show();
       } 	
    }
    $(document).ready(function() {
       setTimeout(function() {
          showHideRegionLocation();
       }, 1000);
       $("select[id^='Status'").on('blur', showHideRegionLocation).on('change', showHideRegionLocation);
       });	
    })(window.jQuery);

Adding JavaScript to a form

  1. Open the edit and/or new form of the list.
  2. Set the form in edit mode
  3. Add the Script Editor Web Part to the page
  4. Edit the SNIPPET and add the following code.

    <script src="../../SiteAssets/System/jquery-3.1.1.min.js" type="text/javascript"></script> 
    <script src="../../SiteAssets/System/EditFormHideShow.js" type="text/javascript"></script>
    
  5. Insert the code en Stop editing the form.
  6. Save the custom JavaScript HideColumns and the jQuery script in the correct location.
  7. The JavaScript will now run and hide or shows the field based on the selected value of the field Status.

 

JavaScript / jQuery: Set fields to read only

With SharePoint we use a lot of lists and libraries to store and share information. But not every bit of information needs to be managed/changed by users. Sometimes a workflow or code is responsible for the information. With default SharePoint it is not possible to set field to read only,  but with the help of jQuery and JavaScript we can. We can add JavaScript to the new and or edit form and disable (read only) any field we want. Make sure to disable the quick option, otherwise user will be able to edit the read only field using this feature.

SharePoint 2013/Online: Disable Quick edit

  1. Open the list or library settings
  2. Open the Advanced settings
  3. Set Quick Edit to No

SharePoint 2010: Disable Datasheet editing

  1. Open the list or library settings
  2. Open the Advanced settings
  3. Set Datasheet to No

Creating the JavaScript

  1. Open your favorite JavaScript Editor
  2. Create a new JavaScript file called HideColumns.js
  3. Add the following base code to the JavaScript file
    // A $( document ).ready() block.
    $( document ).ready(function() {
       
    }
    );
    
  4. Now you need to get the display names of the fields you need to set to read only (disable). Note that you need the correct name of the input, select, text area etc fields. Make sure you do not select the label of the field.
  5. You can use a DOM explorer to find the correct type of fields and the corresponding name. Note that different types are just for different columns
  6. In this example I selected the Multiple Lines of text field
  7. The selected code is
  8. In this code you are able to find the name: Multiple Lines
  9. And the type of field: textarea
  10. Do this for all the fields you need disable
  11. In my example I will disable the following fields
    Name Column Type Input field type
    Multiple Lines Multiple lines of text Textarea
    Title Single line of text Input
    Date Date and time Input
    Choice Choice Select
  12. Depended on the type of field different code is required.
  13. For Input and textarea use
    .attr("disabled", "disabled"); 
    
  14. For select we use
    .prop("disabled", true);
    
  15. The final code will look as follows
    // A $( document ).ready() block.
    $( document ).ready(function() {
        jQuery("input[title='Title']").attr("disabled", "disabled"); 
        jQuery("textarea[title='Multiple Lines']").attr("disabled", "disabled");
        jQuery("input[title='Date']").attr("disabled", "disabled"); 	
        jQuery("select[title='Choice']").prop("disabled", true);
        }
    );
    

Adding JavaScript to a form

  1. Open the edit (or new) form of the list.
  2. Set the edit form in edit mode
  3. Add the Script Editor Web Part to the page
  4. Edit the SNIPPET and add the following code

    <script src="../../SiteAssets/System/jquery-3.1.1.min.js" type="text/javascript"></script> 
    <script src="../../SiteAssets/System/HideColumns.js" type="text/javascript"></script> 
    
  5. Insert the code en Stop editing the form.
  6. Save the custom JavaScript HideColumns and the jQuery script in the correct location
  7. The JavaScript will now run and set the required field on read only when the edit form is opened

SharePoint 2010 Workflow: Capture document set versions

When a user changes a document set the version is not automatically capture, the user can capture the version by manually . Capturing a version manually is down with the Capture Version button located in the Document Set Tab in the ribbon. This is not the a secure way to make sure all versions are captured. With a SharePoint 2010 workflow (not workflow 2013) you can capture all the versions automatically. The solution has been tested on SharePoint 2013 On Premise and SharePoint Online (Office 365).

Solution

There is a small bug with the action Capture a version of the Document Set, the action runs multiple time (equal to the number of columns) and captures multiple versions. To prevent this from happening add a wait action to the workflow, this will make sure that only one version will be captured.

  1. Create a SharePoint 2010 workflow
  2. Configure the workflow to Start Workflow automatically when an item is Changed
  3. Add the action Wait for Field Change in Current Item
  4. Set the action to: Wait for Modified by (column) to equal Current Item: Modified By (column)
  5. Add the action Capture a version of the Document Set, with comment: Version Captured by Workflow.
  6. The full workflow looks like this

SharePoint Timer Job: Workflow Auto Cleanup Job

One of our customers uses workflows to review and approve important project documents. The project board members receive workflow tasks to approval for example the mandate and the project initiation documentation (PID). The customer uses a view to see if the approval workflow is running, complete or not used. After weeks of using the workflow the customer stated that all the workflow information of completed workflows is missing. This is a problem because the customer needs to be able to provide an audit trail of the approval process for important project document.

Cause
The cause of the seaming missing workflow information is the SharePoint timer job Workflow Auto Cleanup Job. The job is responsible for deleting related workflow tasks and the workflows status used in views. The job removes tasks that still exist 60 days after the workflow is completed or cancelled. This is done to prevent the task list to become too large and impact performance. The actual workflow information will not be removed and can still be accessed through the workflow history.

Solution
Because the required audit trail information is not lost we did not change anything to the timer job, to make sure no potential performance issues where introduced.
We introduced the following solution to overcome the default cleanup behavior.

  1. We added a step in the workflow that filled in an extra column, the column contains the information if the workflow has run or not.
  2. The column was removed from the edit page to make sure only the workflow changed the value of the column.
  3. We taught the customer how to use the workflow history, to gain easy access to the audit trail.

Disable the timer job (not recommended)
It is possible to disable the timer job. However, this is not recommended. Disabling the timer job creates a potential impact to performance.

SharePoint: Show all files which have no checked in version

With SharePoint 2010/2013 and the “Check in – Check out” feature enabled documents may seem to disappear and reappear for users without a cause. A common scenario is that colleague 1 saved a document on SharePoint but colleague 2 is unable to find it. While Colleague 1 can still see and find the document. This is a common and a very frustrating situation. This happens when a new file is stored on SharePoint but does not yet have a checked in version. This can happen when multiple files are uploaded to SharePoint and a required column is not filled in or when the setting Require Check Out is enabled. The file(s) will be stored on SharePoint but will be check out and only visible for the up-loader. There is a way for every user to see these hidden checked out documents.

Colleague 1 sees Colleague 2 sees
All documents Check in documents

 
Solution

1. Open the document library where the documents are missing.
2. Click in the ribbon on Library – Settings – Library Settings.
3. Click on Manage files which have no checked in version.
4. All the documents without a checked in version will be displayed.
Checked Out Files
5. If needed the user can take over the ownership and check in the document.

SharePoint 2013: Folders are bad

You have probably heard this SharePoint slogan before: Do not use folders with SharePoint. If you are wondering why this is or need some arguments to convince a customer, then use the following list of reasons.

1. Structure
Changing a folder structure is complicated and time consuming, while changing a metadata structure is easier.

2. Authorization
Setting authorization on folders is possible but before you know it you have created an administrative nightmare

3. Findability
A nested folder structure is only know to the person who created it. Nesting folders will result in semi hidden files.

4. URL length
The URL Length is limited around 256 characters. All the nested folders names will be added to the URL which means you will run into the 256 limit very fast.

5. File Path
When moving files between folders will change the files path. This can result in broken links to the moved file.

6. Duplication
Multiple copies of one file tend to end up in multiple folders. This will result in version conflicts and possible misinformation.

7. Navigation: The user experience with navigating through folders is time consuming and confusing. It is hard to remember where you are and which folders you already checked.

8. Navigation
When a few sub folders down it is very hard to see where you are in the folder structure

9. Filter
You are able to filter within the opened folder, you are unable to filter all the document simultaneously. Filtering all documents simultaneously will speed up the searching process.

10. Sorting
You are able to sort within the opened folder, you are unable to sort all the document simultaneously. Sorting all documents simultaneously will speed up the searching process.

11. Losing files
When you place a file in a wrong folder in a lot of situation you know lost a file.

12. Forcing groups
Files can fall under multiple groups, with folders you need to store the file twice.

SharePoint Custom Grouping with XSLT

For SharePoint solution where the look and feel or clean code is very important we often create custom header.xslt ContentQueryMain.xslt and ItemStyle.xstl files. The files are almost completely empty to provide us with maximal control. This also means we need to recreate functionality that normally works by default. A good example is the ability to group the results.

Solution
1. Create the custom XSLT files and link the files to the Content Query Web Part.
2. The following code is a complete example of a custom Content Query Main XSLT file. This code generates grouping.

<xsl:stylesheet
    version="1.0"
    exclude-result-prefixes="x xsl cmswrt cbq" 
    xmlns:x="http://www.w3.org/2001/XMLSchema"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:cmswrt="http://schemas.microsoft.com/WebPart/v3/Publishing/runtime"
    xmlns:cbq="urn:schemas-microsoft-com:ContentByQueryWebPart">
    <xsl:output method="xml" indent="no" media-type="text/html" omit-xml-declaration="yes"/>

  <xsl:key name="Grouping" match="Row" use="@GroupingColumn" />

  <xsl:template match="/">
 <xsl:for-each select="/dsQueryResponse/Rows/Row[generate-id(.)=generate-id(key('Grouping',@GroupingColumn))]/@GroupingColumn">
  <xsl:sort />
        <xsl:value-of select="."/>
        <xsl:for-each select="key('Grouping', .)">
         <br /><xsl:value-of select="@Title" />
         </xsl:for-each>
        <br/>
      </xsl:for-each>     
    </xsl:template>
</xsl:stylesheet>

3. Change the XSLT where needed

Result
CQWP Custom Grouping