Restoring the top navigation bar of a SharePoint site

It’s a known issue that if you delete the “Top Navigation” menu through the API in SharePoint 2007, you cannot restore it easily. I came across this problem in one of my development sites. When looking for a solution, I found this article, saying you have to do it through the database.

The code below solves the problem programmatically (and yes, it changes the database directly). Of course, it’s an unsupported solution – if you use it, you may get in trouble with Microsoft official support.

string sSiteUrl = "http://moss/sites/yoursite/";
//after the code gets executed, we have to dispose the 
//spweb object, since the Navigation object of the current SPWeb instance will contain wrong information
using (SPSite oSite = new SPSite(sSiteUrl))
{
    using (SPWeb oWeb = oSite.RootWeb)
    {
        //check if the top navigation bar is already there
        SPNavigationNode oTopnav = null;
        try
        {
            oTopnav = oWeb.Navigation.GetNodeById(1002);
        }
        catch (Exception)
        {
            oTopnav = null;
        }

    if (oTopnav == null)
    {
        //we've found out there is no top navigation bar. Let's create one;

        //we create a temporary navigation node pointing back to web site root
        Microsoft.SharePoint.Navigation.SPNavigationNode oTempNode = new Microsoft.SharePoint.Navigation.SPNavigationNode("Navigation", oWeb.ServerRelativeUrl);
        //we add this node to the "global" collection (where quick launch and top nav bar normally live)
        oWeb.Navigation.GlobalNodes.AddAsLast(oTempNode);

        //now the dirty work - go to the database and change the ID of the navigation node
        System.Data.SqlClient.SqlConnection oConn = new System.Data.SqlClient.SqlConnection(oSite.ContentDatabase.DatabaseConnectionString);
        System.Data.SqlClient.SqlCommand oCmd = new System.Data.SqlClient.SqlCommand();
        oCmd.Connection = oConn;
        oCmd.CommandType = System.Data.CommandType.Text;
        //we only update the node which has the same ID as the one we just created, but, to be completely sure that 
        //nothing else gets changed, we add a requirement to have the same siteid and webid
        oCmd.CommandText = @"UPDATE NavNodes SET Eid=1002 WHERE (Eid=" + oTempNode.Id.ToString() + 
             @") AND (SiteId='" + oSite.ID.ToString("D") + "') AND (WebId='" + oWeb.ID.ToString("D") + "')"; ;
        oConn.Open();
        oCmd.ExecuteNonQuery();
        //closing the connection
        oConn.Dispose();
    }
}

} //the oSite object is disposed here

Comments: one response to “Restoring the top navigation bar of a SharePoint site”

  1. Tom

    This Post is awesome!!! It works in SP2013. I get an exception during inserting a TopNavigation entry in the UI after migrating a SP2010 Website to a SP2013 Website. I search more than one day for a solution but could nothing found. This script fixed he issue. I have transformed it into powershell:

     
        clear
        Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
      
        function checkTopNav([String]$siteUrl, [String]$subwebUrl)
        {
            $site = Get-SPSite $siteUrl
            $web = $site.OpenWeb($subwebUrl)
            Write-Host "checking:" $web.Url
            $topNav = $web.Navigation.TopNavigationBar
            if($topNav -eq $null)
            {
                Write-Host "     TopNavigation must be fixed..." -ForegroundColor Yellow
                $firstNode = New-Object Microsoft.SharePoint.Navigation.SPNavigationNode("Home", $web.ServerRelativeUrl)
                $web.Navigation.GlobalNodes.AddAsLast($firstNode) | Out-Null

       $dbConnString = $site.ContentDatabase.DatabaseConnectionString
       $sqlConn = New-Object System.Data.SqlClient.SqlConnection($dbConnString);
        $sqlCmd = New-Object System.Data.SqlClient.SqlCommand
        $sqlCmd.Connection = $sqlConn
        $sqlCmd.CommandType = [System.Data.CommandType]::Text
        $sqlCmd.CommandText = "UPDATE NavNodes SET Eid=1002 WHERE (Eid=" + $firstNode.Id.ToString() +
                              ") AND (SiteId='" + $site.ID.ToString("D") + "') AND (WebId='" + $web.ID.ToString("D") + "')";
        $sqlConn.Open()
        $sqlCmd.ExecuteNonQuery() | Out-Null
        $sqlConn.Dispose()
        Write-Host "     TopNavigation fixed!" -ForegroundColor Green
    }else{
        Write-Host "     nothing to fix" -ForegroundColor Green
    }
    }
    $siteUrl = "http://mySiteCollection:12345"
    checkTopNav $siteUrl "/subweb1"
    checkTopNav $siteUrl "/subweb2"</p>