2

Is there a way good way to replace a WebPart programmatically on a WikiPage and keep the old position? So far I'm able to delete a WebPart and add a new one but since it's a WikiPage where the current WebPart isn't in a specific zone (WebPart.Zone property is empty) I can't figure out how to replace the WebPart and keep the position on the site.

Code I'm using so far:

function 
Add-WebPartToPage($web, $page, $xmlReader, $zoneId, $zoneIndex, $marker)
{  
    $wpManager = $web.GetLimitedWebPartManager($page.Url, [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared);

    $errorMsg = "";
    $wpGuid = [System.Guid]::NewGuid().ToString();
    $wpKey = "g_" + $wpGuid.Replace("-","_"); 

    $wpInstance = $wpManager.ImportWebPart($xmlReader, [ref]$errorMsg);    

    if([string]::IsNullOrEmpty($errorMsg))
    {
        $wpInstance.ID = $wpKey;
        $wpManager.AddWebPart($wpInstance, $zoneId, $zoneIndex);

        $oldContent = $page["WikiField"];
        $wpContent = '<div class="ms-rtestate-read ms-rte-wpbox" contenteditable="false"><div class="ms-rtestate-notify  ms-rtestate-read {0}" id="div_{0}" unselectable="on"></div><div id="vid_{0}" unselectable="on" style="display: none;"></div></div>' -f $wpGuid;
        $newContent = $oldContent.Replace($marker, $wpContent);
        $page["WikiField"] = $newContent;

        $page.Update();
    }
    else
    {
        Write-Host Error: $errorMsg;
    }   
}

function
Delete-WebPartFromPage($web, $page, $wpName)
{
    $wpManager = $web.GetLimitedWebPartManager($page.Url, [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared);
    $webParts = $wpManager.WebParts
    foreach($wp in $($webParts))
    {
        if ($wp.Title.StartsWith($wpName))
        {
            $wpManager.DeleteWebPart($wp);
        }
    }
}
  • Have you tried adjusting the zone index? – Arsalan Shahid Mar 30 '15 at 17:42
  • Yes, but it doesn't work. As far as I know the index is the position withing the zone. When I'm adding a new WebPart to a page I use the "WPZ" zone (the old WebPart was added via the UI and has no zone) – Razze Mar 31 '15 at 6:52
2

Found a solution.

Since the old WebPart had its own div-element which was still in the page (even after deleting the WebPart with the SPLimitedWebPartManager) I was able to swap the IDs in the div without adding any extra HTML-code and thus keep the position.

Here's the updated Code (just the functionality, without error handling etc) if someone runs into the same problems or just needs guidance on how to add/remove/replace WebParts:

function Main-ReplaceWebPart(
[Parameter(Mandatory=$true)][string]$webUrl,
[Parameter(Mandatory=$true)][string]$wpName,
[Parameter(Mandatory=$true)][string]$pageTitle,
[Parameter(Mandatory=$true)][string]$listTitle,
[Parameter(Mandatory=$true)][string]$oldWpTitle)
{
    $web = Get-SPWeb $webUrl;       
    $xmlReader = Get-WebPartXmlReader $web $wpName;
    Replace-WebPart $web $wpName $xmlReader $pageTitle $listTitle $oldWpTitle
    $xmlReader.Close();
}

function 
Get-WebPartXmlReader($web, $wpName)
{
    $wpCatalog = $web.Site.GetCatalog([Microsoft.SharePoint.SPListTemplateType]::WebPartCatalog);
    $wp = $wpCatalog.Items | Where-Object {$_.Name -eq $wpName};
    $wpStream = $wp.File.OpenBinaryStream();
    $xmlReader = New-Object System.Xml.XmlTextReader($wpStream);
    return $xmlReader;
}

function
Replace-WebPart($web, $wpName, $xmlReader, $pageTitle, $listTitle, $oldWpTitle)
{
    $page = Get-SpPage $web $pageTitle $listTitle;
    $wpManager = $web.GetLimitedWebPartManager($page.Url, [System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared);
    $oldWpInfo = Delete-WebPartFromPage $web $page $oldWpTitle $wpManager;
    Add-WebPartToPage $web $page $xmlReader $oldWpInfo[0] $oldWpInfo[1] $oldWpInfo[2] $wpManager;
}

function 
Add-WebPartToPage($web, $page, $xmlReader, $zone, $zoneIndex, $oldWpId, $wpManager)
{  
    $errorMsg = "";
    $wpGuid = [System.Guid]::NewGuid().ToString();
    $wpKey = "g_" + $wpGuid.Replace("-","_"); 

    $wpInstance = $wpManager.ImportWebPart($xmlReader, [ref]$errorMsg);    

    if([string]::IsNullOrEmpty($errorMsg))
    {
        $wpInstance.ID = $wpKey;
        $wpManager.AddWebPart($wpInstance, $zone, $zoneIndex);

        $oldContent = $page["WikiField"];
        $newContent = $oldContent.Replace($oldWpId, $wpGuid);
        $page["WikiField"] = $newContent;

        $page.Update();
    }
    else
    {
        Write-Host Error: $errorMsg;
    }   
}

function
Delete-WebPartFromPage($web, $page, $wpName, $wpManager)
{
    $webParts = $wpManager.WebParts
    $index = 0;
    $zone = "WPZ"
    $wpId = "00"

    foreach($wp in $($webParts))
    {
        if ($wp.Title.StartsWith($wpName))
        {
            $index = $wp.ZoneIndex;
            $wpId = $wp.ID;
            if(![string]::IsNullOrEmpty($wp.Zone)){
                $zone = $wp.Zone;
            }

            $wpManager.DeleteWebPart($wp);
        }
    }
    $wpId = $wpId.substring(2).Replace('_','-');
    return $zone, $index, $wpId;
}

function 
Get-SpPage($web, $pageTitle, $listTitle)
{
    $list = $web.Lists[$listTitle];
    $spPage = $list.Items | Where-Object {$_.Name -eq $pageTitle};
    return $spPage;
}

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.