Adding a 2nd Publishing Target to Your Sitecore Environment, and Why It's a Good Idea

Each of my scaled environments will have at least two publishing targets. Yes, you can use Sitecore's preview tools, but this has its limitations. After decades of working with marketing teams I can say it's always a good idea to have a private URL, only available to the company, where they can review pending changes for an upcoming campaign etc., without having to log in.

Sitecore comes with a standard Web publishing target, so we're going to repurpose this one for Staging and add another which will be public. 

The steps are relatively simple. We need to:

  1. Make a copy of the Web database and name it Public.
  2. Add a configuration file to patch Sitecore so it can use this new database. *
  3. Update the ConnectionStrings.config with the credentials to connect to the new database.
  4. Create a new publishing target in Sitecore.
  5. Publish the site.

* The following guide is for Sitecore 9 and above only since the configuration file is different.

Make a copy of the Web database and name it Public

There's a few ways to copy a SQL database, but there are usually access permission issues, there are stopped services, etc. The following is fool-proof:

Take the Web database offline using SSMS.


Copy LDF and MDF files for web and rename them like so, though your path and database prefix may be different:

  • C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSQL\DATA\Sitecore_Web.mdf
  • C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSQL\DATA\Sitecore_Web.ldf 

And name to:

  • C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSQL\DATA\Sitecore_Public.mdf
  • C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSQL\DATA\Sitecore_Public.ldf

In SSMS, execute the following script, and be sure to change the database prefix and path if you need to. 

USE master;
GO
CREATE DATABASE dev_Web
    ON (FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSQL\DATA\dev_Web.mdf'),
       (FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSQL\DATA\dev_Web.ldf')
    FOR ATTACH;
GO
CREATE DATABASE dev_Public
    ON (FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSQL\DATA\dev_Public.mdf'),
       (FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL14.MSSQLSERVER\MSSQL\DATA\dev_Public.ldf')
    FOR ATTACH;
GO

I've seen cases where the Web database stays visible in SSMS, so though it will say script failed it's only for the creation of that one database, and you can just bring it back online like the first step.


Add a configuration file to patch Sitecore so it can use this new database

Following Helix, create a config in App_Config\Include\Project\ named Project.Website.CASPublishingTargets.config with the following contents. Notice the term Public is in here, which represents the target name in following steps:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:eds="http://www.sitecore.net/xmlconfig/eds/">
    <sitecore role:require="ContentManagement">
        <databases>
            <database id="public" type="Sitecore.Data.DefaultDatabase, Sitecore.Kernel" singleinstance="true">
                <param desc="name">$(id)
                <icon>Images/database_web.png</icon>
                <securityenabled>true</securityenabled>
                <dataproviders hint="list:AddDataProvider">
                    <dataprovider ref="dataProviders/main" param1="$(id)">
                        <disablegroup>publishing</disablegroup>
                        <prefetch hint="raw:AddPrefetch">
                            <childlimit innertext="100">5000</childlimit>
                            <logstats>false</logstats>
                            <template desc="template">{AB86861A-6030-46C5-B394-E8F99E8B87DB}</template>
                            <template desc="template section">{E269FBB5-3750-427A-9149-7AA950B49301}</template>
                            <template desc="template field">{455A3E98-A627-4B40-8035-E683A0331AC7}</template>
                            <template desc="node">{239F9CF4-E5A0-44E0-B342-0F32CD4C6D8B}</template>
                            <template desc="folder">{A87A00B1-E6DB-45AB-8B54-636FEC3B5523}</template>
                            <template desc="language">{F68F13A6-3395-426A-B9A1-FA2DC60D94EB}</template>
                            <template desc="device">{B6F7EEB4-E8D7-476F-8936-5ACE6A76F20B}</template>
                            <item desc="root">{11111111-1111-1111-1111-111111111111}</item>
                            <children desc="main sections">{11111111-1111-1111-1111-111111111111}</children>
                            <cachesize>100MB</cachesize>
                            <template desc="alias">{54BCFFB7-8F46-4948-AE74-DA5B6B5AFA86}</template>
                            <template desc="layout">{3A45A723-64EE-4919-9D41-02FD40FD1466}</template>
                            <template desc="Sublayout">{0A98E368-CDB9-4E1E-927C-8E0C24A003FB}</template>
                            <template desc="xsl rendering">{F1F1D639-4F54-40C2-8BE0-81266B392CEB}</template>
                            <item desc="home">{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}</item>
                            <children desc="main items">{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}</children>
                            <!--  MVC  -->
                            <template desc="Controller rendering">{2A3E91A0-7987-44B5-AB34-35C2D9DE83B9}</template>
                            <template desc="Item rendering">{86776923-ECA5-4310-8DC0-AE65FE88D078}</template>
                            <template desc="Rendering">{92D4A8C4-5754-4E1A-96A6-095BD193E12B}</template>
                            <template desc="Sublayout">{0A98E368-CDB9-4E1E-927C-8E0C24A003FB}</template>
                            <template desc="View rendering">{99F8905D-4A87-4EB8-9F8B-A9BEBFB3ADD6}</template>
                            <!--  Rules  -->
                            <template desc="Action">{F90052A5-B4E6-4E6D-9812-1E1B88A6FCEA}</template>
                            <template desc="Condition">{F0D16EEE-3A05-4E43-A082-795A32B873C0}</template>
                            <template desc="Conditional Rendering Rule">{550B5CEF-242C-463F-8ED5-983922A39863}</template>
                            <template desc="Content Editor Warning Rule">{71A2C881-FBB3-4A23-A187-7FD50A20F924}</template>
                            <template desc="Insert Options Rule">{664E5035-EB8C-4BA1-9731-A098FCC9127A}</template>
                            <template desc="Rule">{D9BDF22F-6E17-47F3-AB64-49C717BA92DA}</template>
                            <template desc="Script">{AB6DD55D-75E3-4A02-9793-7054ED90FCB6}</template>
                            <template desc="Element Folder">{54DAE7CD-BFD8-4E69-9679-75F2AE9F9034}</template>
                            <template desc="Rule Elements Visibility Rule">{271F5CF1-95C7-474D-9F04-06C6EBB20D8F}</template>
                            <template desc="Rules Context Folder">{DDA66314-03F3-4C89-84A9-39DFFB235B06}</template>
                            <template desc="Rules Folder">{8EA2CF67-4250-47A2-AECA-4F70FD200DC7}</template>
                            <template desc="Tag">{1A9B6300-4652-477C-A4B5-B2A64E86B29F}</template>
                            <template desc="Tags Definition">{854BA861-63EA-4A0C-8C7B-541E9A7EC4C1}</template>
                            <template desc="Tags Definitions Folder">{96C8E5DD-63C3-496B-A97C-A3E37E1DACBA}</template>
                            <template desc="Visibility">{AA91A868-02F2-41D3-8B78-1CAD91B4DCAE}</template>
                            <template desc="Validation Result">{29045375-C15F-4E69-B873-75C3F5C1814B}</template>
                            <template desc="Validation Rule">{0512BDE9-5696-42C4-8C7D-B349EDA9CEF9}</template>
                        </prefetch>
                    </dataprovider>
                </dataproviders>
                <propertystore ref="PropertyStoreProvider/store[@name='$(id)']"></propertystore>
                <remoteevents.eventqueue>
                    <obj ref="eventing/eventQueueProvider/eventQueue[@name='$(id)']"></obj>
                </remoteevents.eventqueue>
                <archives hint="raw:AddArchive">
                    <archive name="archive"></archive>
                    <archive name="recyclebin"></archive>
                </archives>
                <cachesizes hint="setting">
                    <data>2000MB</data>
                    <items>1000MB</items>
                    <paths>5000KB</paths>
                    <itempaths>10MB</itempaths>
                    <standardvalues>1500KB</standardvalues>
                </cachesizes>
                <engines.dataengine.commands.addfromtemplateprototype>
                    <obj type="Sitecore.Buckets.Commands.AddFromTemplateCommand, Sitecore.Buckets"></obj>
                </engines.dataengine.commands.addfromtemplateprototype>
            </database>
        </databases>
        <eventing defaultprovider="sitecore">
            <eventqueueprovider defaulteventqueue="core">
                <eventqueue name="public" type="Sitecore.Data.Eventing.$(database)EventQueue, Sitecore.Kernel">
                    <param ref="dataApis/dataApi[@name='$(database)']" param1="$(name)">
                    <param hint="" ref="PropertyStoreProvider/store[@name='$(name)']">
                </eventqueue>
            </eventqueueprovider>
        </eventing>
        <propertystoreprovider defaultstore="core">
            <store name="public" prefix="public" getvaluewithoutprefix="true" singleinstance="true" type="Sitecore.Data.Properties.$(database)PropertyStore, Sitecore.Kernel">
                <param ref="dataApis/dataApi[@name='$(database)']" param1="$(name)">
                <param resolve="true" type="Sitecore.Abstractions.BaseEventManager, Sitecore.Kernel">
                <param resolve="true" type="Sitecore.Abstractions.BaseCacheManager, Sitecore.Kernel">
            </store>
        </propertystoreprovider>
    </sitecore>
</configuration>

 

Update the ConnectionStrings.config with the credentials to connect to the new database

Open ConnectionStrings.config and copy the "web" database, naming it "preview" with, using the new database you created in step 1.

<add name="web" connectionString="Data Source=.;Initial Catalog=Web;User ID=[user];Password=[password]" />
<add name="public" connectionstring="Data Source=.;Initial Catalog=Public;User ID=[user];Password=[password]" />


Create a new publishing target in Sitecore

You'll want to make the publishing targets a bit easier to understand, so we'll rename both of them in Content Editor.

  1.  Go to /sitecore/system/Publishing targets and rename the Internet target "Staging Site" and check the field to indicate it's a Preview publishing target.
  2. Duplicate this item and name it Public Site, set its field Target database to "public", and uncheck the Preview field.


Publish the site

Now that this target is set up you should publish the entire site to it just to be safe. You can now configure the Content Management instance to use it, or a new Content Delivery server. Good luck!