1

In a corporate publishing site, we are using composite looks to allow site managers to choose a branded color scheme.

Basically, we have branded the portal using two css files. A main.css file that contains most of the rules, and which is located in the Style library. And another theme.css that contains all the rules that are dependent on the theme.

So the users can choose their color scheme using the "Change appearance" menu in site settings.

This is working quite well (some gotchas related to the system master page, but that's out of scope).

However, we have some changes to implements in the theme.css file. Because of the composite look engine, the changes in this file won't be reflected until the theme is applied again.

Because there are many area in the portal, it's out of question to manually regenerate the theme on all sub sites.

Is there any way to force the regeneration of the theme?

If required, a powershell script can be used. I gave a try:

function ReapplyTheme{
    param(
        [Microsoft.SharePoint.SPWeb]$Web
    )

    $file=$web.GetFile($web.ServerRelativeUrl.TrimEnd('/') + "/_catalogs/theme/15/Palette_rouge.spcolor")
    $theme=[Microsoft.SharePoint.Utilities.SPTheme]::Open("Name of my theme", $file)
    $theme.ApplyTo($web, $false)

}

But this script breaks subsite. Moreover, color palette and theme name is hardcoded... Maybe there is somewhere to look after the values?

1

I see you managed to solve the issue using the PowerShell script and checking if a theme is applied, etc.

Just for your info though, on the SPTheme class you can find some static methods:

  • To get the current theme, you can use the static method OpenAppliedTheme
  • To regenerate them themed styles you can use the static method EnforceThemedStylesForWeb
  • Or you could simply reapply the current theme using the ApplyTo method

Of course you could use these methods in your PowerShell script as well.

public static void ReapplyCurrentComposedLook(SPWeb web)
{
  // try to get the currently applied theme
  SPTheme theme = SPTheme.OpenAppliedTheme(web);
  if (theme == null)
  {
    // return if no theme is applied
    return;
  }

  // reinforce the styles for the web..
  SPTheme.EnforceThemedStylesForWeb(web);

  // .. or simply reapply the whole theme.
  theme.ApplyTo(web, true);
}
  • <sarcasm>thanks Microsoft; Thanks for the lack of practical documentation</sarcarsm>. thanks to the community to share actual solutions when it exists :) – Steve B Oct 1 '14 at 14:12
1

I finally made my script evolves.

Basically, in each subweb I look after the composed look with order "0", which is the current theme. I also check the properties of the web object to check if the web is setup to inherits its parent or not.

Using the data from the found composed look, I can regenerate the them.

Seems to work quite well.

Here is the script:

#requires -PSSnapin Microsoft.SharePoint.PowerShell

param(
    [Parameter(Mandatory = $true, Position=0, ParameterSetName='SPSite')]
    [Microsoft.SharePoint.PowerShell.SPSitePipeBind]$Site,
    [Parameter(Mandatory = $true, Position=0, ParameterSetName='SPWeb')]
    [Microsoft.SharePoint.PowerShell.SPWebPipeBind]$Web,
    [Parameter(Position=1)]
    [Switch]$Recurse=$true
    #TODO: add argument to allow specify a specific theme, instead of regenerating it
)

$actualWeb = if(-Not $Web) {
    $site.Read().RootWeb
} else{
    $Web.Read()
}


function Get-ThemeData{
    param(
        [Parameter(Mandatory=$true)]
        [Microsoft.SharePoint.SPWeb]$Web
    )


    $designList = $Web.GetList($web.ServerRelativeUrl.TrimEnd('/') + "/_catalogs/design")
    $query = New-Object Microsoft.SharePoint.SPQuery
    $query.ViewFieldsOnly = $true
    $query.ViewFields = "<FieldRef Name='ThemeUrl' /><FieldRef Name='ImageUrl' /><FieldRef Name='FontSchemeUrl' />"
    $query.Query = "<Where><Eq><FieldRef Name='DisplayOrder' /><Value Type='Number'>0</Value></Eq></Where>";

    $designItem = $designList.GetItems($query)[0]

    $resultProperties = @{
        "Web" = $Web.ServerRelativeUrl
        "FontSchemeUrl" = $designItem["FontSchemeUrl"]
        "ThemeUrl" = $designItem["ThemeUrl"]
        "ImageUrl" = $designItem["ImageUrl"]
        "InheritsThemedCssFolderUrl" = [bool]::Parse($web.AllProperties["__InheritsThemedCssFolderUrl"])
        "InheritsCustomMasterUrl" = [bool]::Parse($web.AllProperties["__InheritsCustomMasterUrl"])
        "InheritsMasterUrl" = [bool]::Parse($web.AllProperties["__InheritsMasterUrl"])
        MasterUrl=$web.MasterUrl
        CustomMasterUrl=$web.CustomMasterUrl
    }

    New-Object PSObject -Property $resultProperties 
}

function Process-SPWeb{
    param(
        [Parameter(Mandatory=$true)]
        [Microsoft.SharePoint.SPWeb]$Web
    )
    Write-Host "Traitement de $($web.ServerRelativeUrl)"

    $themeData = Get-ThemeData $Web

    if(-not $themeData.InheritsThemedCssFolderUrl){
        $color = if($themeData.ThemeUrl) { $web.GetServerRelativeUrlFromUrl((New-Object Microsoft.SharePoint.SPFieldUrlValue($themeData.ThemeUrl)).Url) }
        $font = if($themeData.FontSchemeUrl) { $web.GetServerRelativeUrlFromUrl((New-Object Microsoft.SharePoint.SPFieldUrlValue($themeData.FontSchemeUrl)).Url) }
        $image = if($themeData.ImageUrl) { $web.GetServerRelativeUrlFromUrl((New-Object Microsoft.SharePoint.SPFieldUrlValue($themeData.ImageUrl)).Url) }


        $web.ApplyTheme($color,$font,$image, $false)
        $web2 = Get-SPWeb $web.url
        $web2.MasterUrl = $themeData.MasterUrl
        $web2.CustomMasterUrl = $themeData.CustomMasterUrl
        $web2.Update()
        $web2.Dispose()

        Write-Warning "Thème regénéré sur $($web.ServerRelativeUrl)"
    }

    if($Recurse){
        $Web.Webs | % { Process-SPWeb $_ }

    }

}


Process-SPWeb $actualWeb

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.