Sitecore Recycle Bin - Finding Items by ID

12 February 2018

Short blog post here. Today I was trying to recover some content for a user and managed to restore a page, but soon realised that several related datasource items were also missing. When a datasource item has been removed from Sitecore, the rendering details of the components will show a raw ID in the datasource instead of the usual Sitecore path.

My first thought was to simply paste an ID into the search box of the recycle bin, but alas this is restricted to 20 characters. Some detective work by Maras Musielak reveals that this search runs against the Item Name, Item Path, and the user who archived the item.

This is the basic API code to get an instance of the archive class which is then used to get an archival ID of a specified item and then retrieve the archive entries for that ID. Interestingly, if the ID you are searching for returns no results, Archive.GetEntries(ID) actually returns everything in the recycle bin!

var db = Sitecore.Configuration.Factory.GetDatabase("master");
 var archiveName = "recyclebin";
var archive = Sitecore.Data.Archiving.ArchiveManager.GetArchive(archiveName, db);
var itemId = Sitecore.Data.ID.Parse(ItemId.Text);
var archivalId = archive.GetArchivalId(itemId);
var data = archive.GetEntries(new ID(archivalId)).Where(ent => ent.ItemId == itemId);

Below is a very rough and ready aspx page which you can place in your Website\Sitecore\admin folder to allow retrieval of items by ID and restoring of those items.

<%@ Page Language="C#" AutoEventWireup="true" Debug="true" %>
<%@ Import Namespace="Sitecore.Data" %>
<%@ Import Namespace="Sitecore.Data.Archiving" %>
<%@ Import Namespace="System.Linq" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title>Oscar - Recycle Bin Utility</title>
        <link rel="Stylesheet" type="text/css" href="/sitecore/shell/themes/standard/default/WebFramework.css" />
        <link rel="Stylesheet" type="text/css" href="./default.css" />
        <style type="text/css">
            table.information {
                border-spacing: 2px;
                border-collapse: separate;
            }

            table.information td{
                padding: 0;
            }

            table.information.custom-controls tr:last-of-type td:last-of-type {
                text-align: right;
            }

            .information td.button {
                text-align: right;
            }

            .information input[type="submit"] {
                min-width: 80px;
            }

            .information input[type="text"], .information input[type="password"] {
                width: 500px;
            }

            .information tr td:first-of-type label {
                text-align: right;
                display: inline-block;
                min-width: 80px;
            }

            .automargin {
                margin-left: auto;
                margin-right: auto;
            }
            
            /* styles to align aspnet login controls */
            .aspnet-login input[type="checkbox"] {
                margin-left: 85px;
            }

            .aspnet-login input[type="submit"] {
                margin-right: 5px;
            }

            div.chunk {
              width: auto;
            }
        </style>
      <script type="text/C#" runat="server">

          protected Sitecore.Data.Archiving.Archive GetArchive()
          {
            var db = Sitecore.Configuration.Factory.GetDatabase("master");
            var archiveName = "recyclebin";
            return Sitecore.Data.Archiving.ArchiveManager.GetArchive(archiveName, db);
          }

          protected void SearchRecycleBin_Click(object sender, EventArgs e)
          {
            var archive = GetArchive();
            var itemId = Sitecore.Data.ID.Parse(ItemId.Text);
            var archivalId = archive.GetArchivalId(itemId);
            var data = archive.GetEntries(new ID(archivalId)).Where(ent => ent.ItemId == itemId);
            ResultList.DataSource = data;
            ResultList.DataBind();
          }

          protected void ResultList_ItemCommand(object sender, RepeaterCommandEventArgs e)
          {
            if (e.CommandName == "Restore")
            {
              Guid archivalId;
              if (Guid.TryParse(e.CommandArgument as string, out archivalId))
              {
                var archive = GetArchive();
                archive.RestoreItem(archivalId);
              }
            }
          }



      </script>
    </head>
    <body>
        <form id="Form1" runat="server" class="wf-container">
            <div class="wf-content" style="overflow: hidden;">
                <h1><a href="/sitecore/admin/">Administration Tools</a> - Oscar Recycle Bin Viewer</h1>
                <br />
                <br />
                <div class="root">
                    <table>
                        <tr>
                            <td class="top">
                                <div class="chunk">
                                    <h3>Enter Item ID Here:</h3>
                                    <hr />
                                    <table class="information automargin custom-controls">
                                        <tr>
                                          <td>
                                            <asp:Label id="LabelContextItem" AssociatedControlId="ItemId" Text="Item ID:" runat="server" />
                                          </td>
                                          <td>
                                            <asp:TextBox ID="ItemId" runat="server" /></td>
                                        </tr>
                                        <tr>
                                            <td> </td>
                                            <td><asp:Button ID="SearchRecycleBin" runat="server" Text="Search Recycle Bin" OnClick="SearchRecycleBin_Click" /></td>
                                        </tr>
                                    </table>
                                </div>
                            </td>
                        </tr>
                      <tr>
                        <asp:Repeater ID="ResultList"
                                      OnItemCommand="ResultList_ItemCommand"
                                      runat="server">
                          <HeaderTemplate>
                            <table>
                            <tr>
                              <th>Name</th>
                              <th>Path</th>
                              <th>Date (UTC)</th>
                              <th>By</th>
                            </tr>
                          </HeaderTemplate>

                          <ItemTemplate>
                            <tr>
                              <td>
                                <%# Eval("Name") %>
                              </td>
                              <td>
                                <%# Eval("OriginalLocation") %>
                              </td>
                              <td>
                                <%# Eval("ArchiveDate") %>
                              </td>
                              <td>
                                <%# Eval("ArchivedBy") %>
                              </td>
                              <td>
                                <asp:Button ID="Restore"
                                            Text="Restore"
                                            CommandName="Restore"
                                            CommandArgument='<%# Eval("ArchivalId") %>'
                                            UseSubmitBehavior="false"
                                            runat="server"/>
                              </td>
                            </tr>
                          </ItemTemplate>
                        </asp:Repeater>
                      </tr>
                    </table>
                </div>
            </div>
        </form>
    </body>
</html>
Tags: Sitecore API
comments powered by Disqus