O resultado gerado por um Sitecore Sheer UI dialog apagava o valor do campo Rich Text Editor. Qual era o problema e como resolvi?

Ao trabalhar com Sitecore depois de um tempo, nos deparamos com requisitos a serem implementados que são bem corriqueiros, como criar um botão no Rich Text editor e realizar alguma ação. Porém e se o botão abrir uma janela de Sheer UI, da qual você precise selecionar um valor e atualizar um campo no rich text editor?

Você conseguiria mas o valor do campo pode ser sobrescrito. Se você está procurando por uma solução para esse comportamento descrito, continue lendo 🙂

CENARIO

Neste cenário eu criei um botão no Rich Text Editor e quando o usuário clicava o botão, um comando de abrir uma janela de Sheer UI era disparado, e o usuario poderia selecionar de uma lista e depois um link era gerado e mostrado no editor a partir do valor selecionado. O problema, como mencionei a pouco, é que o restante do conteúdo era apagado. O link que eu estava gerando era similar a qualquer link de midia gerado pelo Sitecore:

 

<a href="~/media/c91e6ce67216446c8c2af1ae5d2a8120.ashx">PDF_test</a>

O meu diálogo Sheer herda de Sitecore.Web.UI.Pages.DialogForm. Eis como o método OnOk do meu diálogo foi definido(adaptado para este post). A variável dialogValue era uma string que continha um link, e passava ele para a janela de Sheer.

protected override void OnOK(object sender, EventArgs args)
{
        //previous code cleared from this question
        //this would bring the link to be assigned to the dialog
        var dialogValue = AssetService.GetValue();
        SheerResponse.SetDialogValue(dialogValue);
        base.OnOK(sender, args);
}

Este era o command que eu implementei no arquivo RichTextCommands.js para fazer a chamada da janela de Sheer:

Telerik.Web.UI.Editor.CommandList["SelectAsset"] = function (commandName, editor, args) {
    scEditor = editor;

    editor.showExternalDialog(
        "/sitecore/shell/default.aspx?xmlcontrol=SelectAsset&currentItemId=" + scItemID + "&assetType=link",
        null, //argument
        1105,
        700,
        scInsertSitecoreLink,
        null,
        "Asset",
        true, //modal
        Telerik.Web.UI.WindowBehaviors.Close, // behaviors
        false, //showStatusBar
        false //showTitleBar
    );
};


SOLUÇÃO

Para resolver esse problema existem algumas coisas que precisam serem feitas. Abaixo seguem 4 passos que fiz para resolvê-las.

1- Defina as funções de javascript em um arquivo de js:


function GetDialogArguments() {
	return getRadWindow().ClientParameters;
}

function getRadWindow() {
	if (window.radWindow) {
		return window.radWindow;
	}

	if (window.frameElement && window.frameElement.radWindow) {
		return window.frameElement.radWindow;
	}

	return null;
}

var isRadWindow = true;

var radWindow = getRadWindow();

if (radWindow) {
	if (window.dialogArguments) {
		radWindow.Window = window;
	}
}

function scClose(url, text) {
    //builds the link and anchor name
	var returnValue = {
		url: url,
		text: text
	};

	getRadWindow().close(returnValue);

}

function scCancel() {
	getRadWindow().close();
}

Note a função scClose. Esta função será referenciada abaixo on método OnOk. Em outras palavras, quando o usuário clica na janela de Sheer no botão OK, e depois que o processamento do lado do servidor terminou, esta função de js é chamada no lado do cliente(ver passo 4)

2- Referencie o arquivo de js que você criou no arquivo XML do seu diálogo Sheer.

3- Na classe de code beside do diálogo adicione uma nova propriedade. No meu caso ela ficou definida assim:

protected string Mode{
     get{
          string str = StringUtil.GetString(this.ServerProperties["Mode"]);
          if (!string.IsNullOrEmpty(str))
               return str;
          return "shell";
      }
      set{
          Assert.ArgumentNotNull((object)value, "value");
          this.ServerProperties["Mode"] = (object)value;
      }
}

4- No método OnOk agora a variável dialogValue é um objeto com duas propriedades: Url e Text. Após realizar essas mudanças o método OnOk ficou definido assim:


          var dialogValue = AssetService.GetRawValue();          
          //Rich text asset
          if (this.Mode == "webedit" || dialogValue == null)
          {
                SheerResponse.SetDialogValue(StringUtil.EscapeJavascriptString(dialogValue));
                base.OnOK(sender, args);
          }
          else
               //writes the url and link name(dialogValue .Value). This will build the link on the Rich Text Editor
               SheerResponse.Eval("scClose(" + StringUtil.EscapeJavascriptString(dialogValue.Url) + "," + StringUtil.EscapeJavascriptString(dialogValue.Value) + ")");
            

Note que na clausula else, o método base.OnOk não está sendo chamado mas sim o método Eval referenciando a função scClose e passando os parametros url e text(utilizados para construir o link). No fim o resultado era um link no mesmo formato descrito no início deste post mas o conteúdo do campo Rich Text editor não era mais apagado

 

Configurando um workflow em todos os templates utilizando SPE

Recentemente eu tive que implementar um novo workflow em um projeto de Sitecore. Todos os templates existentes necessitariam utilizar o novo workflow. Eu até poderia ir manualmente em cada template e atualizar manualmente, mas como eu sou um desenvolvedor, normalmente quando eu tenho que realizar uma atividade repetitiva eu penso em formas de automatizá-la. Neste caso, como haviam alguns templates a serem atualizados, eu decidi escrever um script de powershell para atualizar todos.

O módulo Sitecore Powershell Extensions é otimo para automatizar atividades como essa, das quais normalmente necessitam de passos manuais e repetitivos. Se você é um desenvolvedor de Sitecore e ainda não utiliza, eu recomendo dar uma olhada. Esse módulo vem com várias funcionalidades interessantes como relatórios, integrações com o Editor de Conteúdo, Painel de controle, além de vir com muitos comandos que facilitam a construção de scripts para manipular os itens em Sitecore.

Script

Voltando ao cenário descrito no início do post, eu criei o seguinte script(ligeiramente adaptado para o fim do post):

$templates = Get-ChildItem -Path "/sitecore/templates/My Project Templates" -Recurse | Where-Object { $_.Name -match "__Standard Values" } | ForEach-Object{
       $_.__Workflow = "{A5BC37E7-ED96-4C1E-8590-A26E64DB55EA}"
}

O que esse script está fazendo é pegando todos os itens standard values que são descendentes do caminho “/sitecore/templates/My Project Templates”, que é o caminho onde os templates do meu projeto estavam. Depois ele percorre os resultados e configura o no campo workflow o GUID do workflow que eu havia criado, que nesse caso era “{A5BC37E7-ED96-4C1E-8590-A26E64DB55EA}”.

Simples certo? Bem é por isso que eu pessoalmente gosto de utilizar o módulo Sitecore Powershell Extensions sempre que eu posso, pois ele facilita muito as coisas. Se você tiver interesse, é possivel fazer o download diretamente daqui.  Você também pode ver o livro online que tem muitos exemplos interessantes e uma documentação bem completa sobre o módulo, além de ter o suporte da comunidade no canal do Slack #module-spe.

Same post in english here

Como implementar um site de pre-produção em Sitecore? Eis algumas dicas de como fazer isso

Um requisito muito comum para quem trabalha com Sitecore é a necessidade dos autores de conteúdo de enviar URLs para outras pessoas, normalmente pessoas que não tem acesso ao Sitecore. Se essas pessoas normalmente não tem acesso, como elas podem revisar o conteúdo antes de ser publicado?

Conforme descrito aqui. na versão 7.2 foi adicionada a possibilidade de implementar a publicação para ambientes de pré-produção. No link mencionado tem algumas dicas interessantes de como setar um ambiente assim. Eis aqui outras que podem ser úteis para quem quiser configurar um ambiente desse.

1- Você precisa configurar um site definition. Para fazer isso voce pode usar o arquivo SiteDefinitions.config, localizado na pasta App_Config/Include e adicionar a definição conforme o exemplo:

<site name=”preprod” patch:before=”site[@name=’website’]” virtualFolder=”/” physicalFolder=”/” rootPath=”/sitecore/content” content=”preprod” startItem=”/home” database=”preprod” domain=”sitecore” allowDebug=”true” cacheHtml=”false” htmlCacheSize=”0″ registryCacheSize=”0″ viewStateCacheSize=”0″ xslCacheSize=”0″ filteredItemsCacheSize=”0″ enablePreview=”true” enableWebEdit=”true” enableDebugger=”true” disableClientData=”false” hostName=”preview.mywebsite.com”/>

Note a propriedade hostName. Esta é a url que os autores de conteúdo irão prover para os usuários que não tem acesso ao sitecore. Outra coisa importante de notar aqui é o banco “preprod”. Ver item 3.

2- No IIS, adicione o binding preview.mywebsite.com no seu site. Quando o fizer essa URL vai resolver no seu site.

3- Adicone um novo banco de dados master ou crie uma cópia do existente e adicione novamente ao SQL Server. Note abaixo como deve ficar a connection string:

<add name=”preprod” connectionString=”user id=myuser;password=mypassword;Data Source=MyDataSource;Database=sitecore_master_preview” />

4- No Sitecore, crie um novo publication target. Para fazer isso, abra o Editor de Conteúdo e navegue até o caminho e crie um novo item, que no exemplo abaixo eu nomeei Preprod. Depois disso sete o valor para checado no campo  “Preview publishing target”

5-  Atualize o workflow para ter uma ação do tipo __OnSave para publicar para o banco preprod. Isso é importante para garantir que o conteúdo sendo editado esteja disponível para visualização no site de pré-produção:

Note que o parâmetro tem o mesmo nome que o publishing target recém criado.

 

6-  Caso você esteja lidando com um ambiente escalável você precisa configurar alguns itens também. Sugiro que você revise o scaling guide do Sitecore para isso mas os itens a seguir já vão te ajudar nisso.

If you are dealing with an scaled environment you need to make sure that the publishing is properly configured. Please review Sitecore’s scaling guide for more details about this but items 7 and 8 will help you with that.

7- Você precisa limpar a cache do site preprod quando uma publicação ocorrer. Para fazer isso você precisa adicionar uma definição no event publis:end e publish:end:remote conforme abaixo:

 <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
 <sitecore>
       <events>
            <event name="publish:end">
                  <!--<handler type="Sitecore.Modules.RSS.PublishingHandler, Sitecore.Modules.RSS" method="OnPublishEnd"/>-->
                 <handler type="Sitecore.Publishing.HtmlCacheClearer, Sitecore.Kernel" method="ClearCache">
                       <sites hint="list">
                           <patch:delete />
                       </sites>
                       <sites hint="list">
                            <site>website</site>
                            <site>preprod</site>
                       </sites>
                </handler>
            </event>
            <event name="publish:end:remote">
                   <handler type="Sitecore.Publishing.HtmlCacheClearer, Sitecore.Kernel" method="ClearCache">
                          <sites hint="list">
                               <patch:delete />
                          </sites>
                          <sites hint="list">
                                <site>website</site>
                                <site>preprod</site>
                          </sites>
                   </handler>
            </event>
        </events>
</sitecore>
</configuration>

Continue reading

Ever wonder how to implement a pre-production preview website on Sitecore? Here are a few hints to get that done!

It is a common request from content authors in Sitecore that from time to time they needed to send internal URL to non-Sitecore users. Since these users generally do not have access to Sitecore how can they review the content before it goes live, for example?
As described here, on Sitecore 7.2 it was added the ability to implement pre-production publishing. Take a look at the link provided with a few useful hints to setup the pre-production publishing. Here are others that need to be done in order to get that working properly.

1- You need to have a site definition in place. To do that you can use the SiteDefinition.config file, located under App_Config/Include to add your site definition. Here is one example:

<site name=”preprod” patch:before=”site[@name=’website’]” virtualFolder=”/” physicalFolder=”/” rootPath=”/sitecore/content” content=”preprod” startItem=”/home” database=”preprod” domain=”sitecore” allowDebug=”true” cacheHtml=”false” htmlCacheSize=”0″ registryCacheSize=”0″ viewStateCacheSize=”0″ xslCacheSize=”0″ filteredItemsCacheSize=”0″ enablePreview=”true” enableWebEdit=”true” enableDebugger=”true” disableClientData=”false” hostName=”preview.mywebsite.com”/>

Note the hostName property. This is the url that the content authors will provide to non-sitecore users. Also the property database points to a new database “preprod”

2- On IIS, add the preview.mywebsite.com to the binding of your website. When you do that you will enable it to be resolved by your website.

3- Attach a new master database or create a snapshot of the existing one and re-attach to SqlServer. The connection string for this new database should be set to preprod:

<add name=”preprod” connectionString=”user id=myuser;password=mypassword;Data Source=MyDataSource;Database=sitecore_master_preview” />

4- On Sitecore create a new publication target. To do that, open the content editor and navigate to the path /sitecore/system/Publishing targets and create a new target which I`m naming preprod. After you do that check the checkbox “Preview publishing target”

5- Update your workflow definition to have the __OnSave action to publish it to the preprod database. This is required to help content authors when creating the content and having the content landing on the preview site:

Note that the target parameter has the same name as the publishing target created.

 

6- If you are dealing with an scaled environment you need to make sure that the publishing is properly configured. Please review Sitecore’s scaling guide for more details about this but items 7 and 8 will help you with that.

7- Make sure you preprod site is getting it’s cache cleared when the publishing is happening. To do that need to add it’s definition to the publish:end and publish:end:remote configurations to a HtmlCacheClear file definition.

Here is an example of how it could be defined:

 <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
 <sitecore>
       <events>
            <event name="publish:end">
                  <!--<handler type="Sitecore.Modules.RSS.PublishingHandler, Sitecore.Modules.RSS" method="OnPublishEnd"/>-->
                 <handler type="Sitecore.Publishing.HtmlCacheClearer, Sitecore.Kernel" method="ClearCache">
                       <sites hint="list">
                           <patch:delete />
                       </sites>
                       <sites hint="list">
                            <site>website</site>
                            <site>preprod</site>
                       </sites>
                </handler>
            </event>
            <event name="publish:end:remote">
                   <handler type="Sitecore.Publishing.HtmlCacheClearer, Sitecore.Kernel" method="ClearCache">
                          <sites hint="list">
                               <patch:delete />
                          </sites>
                          <sites hint="list">
                                <site>website</site>
                                <site>preprod</site>
                          </sites>
                   </handler>
            </event>
        </events>
</sitecore>
</configuration>

Continue reading

Sitecore Commerce: Adventure works catalog did not get imported. How to do that manually?

If you are working with Sitecore Commerce and you follow the setup guideline you know that it imports the Adventure works catalog into Commerce Server and Sitecore. What if something goes wrong and you need to import it manually?

If you are reading this most likely you ran into the same issue I did recently. The import process happens when you are running the powershell command InitializeCSSite but if you open Commerce server and it’s not showing up here is what you need to do:

1) Open Commerce Server, and on the Catalogs click import.

2) Browse to your Sitecore Website folder and look for the catalog.xml file i.e. C:\myproject\Website\SitecoreCommerce\Data\Catalog\catalog.xml. Once you do that you should be see on the Status View into Commerce Server the following:

3) That’s it. Now if you open Sitecore content Editor and navigate to the Catalogs root (/sitecore/Commerce/Catalog Management/Catalogs) you should see the Adventure Wors Catalog available on the Selected Catalogs field. Clicking the checkbox should make it show under the Catalogs Item as bellow:

Sitecore Commerce: O catálago Adventure works não foi importado. Como fazê-lo manualmente?

Se você está trabalhando com Sitecore Commerce e está seguindo o guia de instalação você sabe que durante a instalação, o catálogo Adventure works é importado no Commerce Server e no Sitecore. E se ocorrer um problema durante a instalação, como posso fazê-lo manualmente?

Se você continuou lendo é porque possivelmente está tendo o mesmo problema que eu tive recentemente. O processo de importação ocorre quando você roda o commando de powershell InitializeCSSite. Porém se você abrir o Commerce Server e ele não tiver sido importado, eis o que você pode fazer:

1) Abra o Commerce Server e no link Catalogo click importar.

2) Navegue até o caminho da sua instância do Sitecore e procure pelo arquivo catalog.xml, por exemplo, C:\myproject\Website\SitecoreCommerce\ Data\Catalog\catalog.xml. Depois de fazer isso e clicar em OK você deverá ver, na aba Status do Commerce Server o seguinte:

3) É isso. Agora se você abrir o Editor de Conteúdo do Sitecore e navegar até o caminho do item Catalogs(/sitecore/Commerce/Catalog Management/Catalogs) você deverá ver o catálogo Adventure Wors disponível para ser selecionado, no campo Selected Catalogs. Clicando o checkbox deverá fazer o catálogo ficar disponível abaixo do item Catalogs:

Updating renderings properties using Sitecore Powershell Extensions

Have you ever needed to update a rendering property on several items in your Sitecore content tree and didn’t want to go through the process manually? Well recently I had, and if I had to do it manually one by one, it take a lot of time as I had several items I needed to perform such task. Whenever you face a situation like this, you might want to consider using the powershell extensions module.

By the way If you are working with Sitecore and you are not familiar with the powershell extensions module I highly recommend you start using it. It can save you a lot of time. You can download the module at the marketplace.

So in this scenario I wanted to update a rendering on all items of a specific template and set the caching “Vary By Data” property to checked on all of them.

Here is how you can easily do that by running this script:

$items = Get-ChildItem -Recurse | Where-Object {$_.TemplateID -match “{79A0F7AB-17C8-422C-B927-82A1EC666ABC}”} | ForEach-Object {

$renderingInstance = Get-Rendering -Item $_ -Rendering $rendering
if($renderingInstance){
$renderingInstance.VaryByData = 1
Set-Rendering -Item $_ -Instance $renderingInstance
}

}

 

So what this script is doing is pretty straight forward but in any case here is the explanation on what it does.

It is getting all descendants of the Sitecore Context, in this case sitecore\content\home and it is filtering for all descendants that have the TemplateID guid as “{79A0F7AB-17C8-422C-B927-82A1EC666ABC}”.
Next it will loop on the results and set to the renderingInstance variable the rendering. If it’s not null it sets the VaryByData property to 1(checked) and execute the Set-Rendering command.
At this point all renderings on the items will have been set to “Vary By Data” as checked as shown bellow:

Atualizando as propriedades dos renderings com Sitecore e Powershell Extensions

Voce já teve que atualizar uma propriedade em um rendering em vários itens da árvore de conteúdo e não queria atualizá-los manualmente? Eu recentemente tive que fazer isso e abaixou vou descrever como fazê-lo, utilizando o módulo Powershell Extensions.

Quando você tiver um cenário parecido com esse, eu recomendo você utilizar o módulo Powershell Extensions.

Se você trabalha com Sitecore e não conhece esse módulo, eu recomendo que começe a usar. Você pode ganhar bastante tempo utilizando ele. Você pode fazer o download do módulo na marketplace da Sitecore.

No cenário deste post, eu queria atualizar um rendering em todos os itens de um determinado template e setar a propriedade de cache “Vary By Data” para checado em todos os itens.

Para fazer isso basta rodar este script:

$items = Get-ChildItem -Recurse | Where-Object {$_.TemplateID -match “{79A0F7AB-17C8-422C-B927-82A1EC666ABC}”} | ForEach-Object {

$renderingInstance = Get-Rendering -Item $_ -Rendering $rendering
if($renderingInstance){
$renderingInstance.VaryByData = 1
Set-Rendering -Item $_ -Instance $renderingInstance
}

}

Caso você tenha alguma dúvida sobre o que ele está fazendo vou detalhar melhor.

Ele esta pegando todos os itens descendentes o item de contexto do Sitecore, que nesse caso é sitecore\content\home e está filtrando por todos os itens que sejam do template com o ID igual a  “{79A0F7AB-17C8-422C-B927-82A1EC666ABC}”.

Depois ele faz um loop em todos os resultados e pega o rendering de cada item no loop e armazena na variável renderingInstance. Se ela não for nula, ele seta a propriedade VaryByData com o valor 1(checado) e executa o comando Set-Rendering.

A essa altura todos os items que ele percorreu no loop terão a propriedade “Vary By Data” checada, conforme abaixo:

Sitecore Powershell Extensions: Ever wonder how to elevate your session without having to provide your credentials? Here is how

In today’s post we will review an interesting feature in Sitecore Powershell Extensions: How to elevate your session without having to provide your credentials. I’m using on today’s post SPE 4.4.1.29973 and Sitecore 8.2.

The idea for this post came when I was playing around with SPE and everytime I would run a script using ISE I would get prompted for my credentials like shown bellow:

I thought to myself “There has got to be a way to get rid of this popup while I’m still developing the script and want to run and test it”. And I found that actually there is. But this pop-up exists for a reason and you should consider it. But if you are just developing on your local and you know what you are doing keep reading 🙂

I’m logged in as admin(and yes “b” is still my password) so I’m already an admin with elevated privileges right? so what else should I do?

Well there is a section on the “Cognifide.PowerShell.config” config file which essentially guides this behavior:

<userAccountControl>
<gates>

<gate name=”Console” token=”Console”/>
<gate name=”ISE” token=”ISE”/>
<gate name=”ItemSave” token=”ItemSave”/>
</gates>
<tokens>

<token name=”Default” expiration=”00:00:00″ elevationAction=”Block”/>
<token name=”Console” expiration=”00:05:00″ elevationAction=”Password”/>
<token name=”ISE” expiration=”00:05:00″ elevationAction=”Password”/>
<token name=”ItemSave” expiration=”00:05:00″ elevationAction=”Password”/>
</tokens>
</userAccountControl>

 

You might be wondering what are gates and tokens. If you are have a look on this link.

So there are essentially two ways for you to elevate that privilege. One is to increase the expiration time on the ISE token, for example for a few hours or days. But you will have to provide your password at least once. Or you can essentially change to value of the attribute elevationAction.

In the code above it’s set to “Password” which means that you have to provide your password. The other values you can set are Block and Allow.

Block will block the execution of your code even if you provide your password showing you a message like this:

Allow will essentially achieve what you are looking for. You will be able to run scripts as much as you would like without providing your password.

Sitecore Powershell Extensions: Como elevar a sua sessão sem fornecer as credencias

No post de hoje nós vamos revisar uma funcionalidade interessate do módulo Sitecore Powershell Extensions: Como elevar a tua sessão sem fornecer as tuas credenciais. Para este post eu estou utilizando a versão  4.4.1.29973 do módulo e a versão 8.2 de Sitecore.

A idéia deste post veio quando eu estava desenvolvendo um script usando SPE e toda vez que eu queria rodar o script aparecia o pop-up pedindo pela minha senha, conforme mostra abaixo:

Eu pensei comigo mesmo “Deve haver alguma forma de não precisar fornecer as minhas credenciais toda vez que eu rodo o script, já que eu estou desenvolvendo e quero testar apenas”. E eu descobri que tem como.

Porém esse pop-up existe por um motivo e você deve ter isso em consideração. Mas se você estiver desenvolvendo no seu ambiente e você sabe o que está fazendo, continue lendo 🙂

Neste exemplo eu estou logado como admin o que já me daria permissões elevadas correto? O que mais eu preciso fazer?

 

Existe uma seção no arquivo de configuração “Cognifide.PowerShell.config” que essencialmente define esse comportamento:

<userAccountControl>
<gates>

<gate name=”Console” token=”Console”/>
<gate name=”ISE” token=”ISE”/>
<gate name=”ItemSave” token=”ItemSave”/>
</gates>
<tokens>

<token name=”Default” expiration=”00:00:00″ elevationAction=”Block”/>
<token name=”Console” expiration=”00:05:00″ elevationAction=”Password”/>
<token name=”ISE” expiration=”00:05:00″ elevationAction=”Password”/>
<token name=”ItemSave” expiration=”00:05:00″ elevationAction=”Password”/>
</tokens>
</userAccountControl>

Talvez você esteja se perguntando o que são gates e tokens. Se estiver, sugiro a leitura desse link.

Existem então essencialmente duas formas de elevar a sessão. Uma é aumentar o tempo de expiração do token ISE, por exemplo para algumas horas ou dias. Mas você terá que fornecer a sua senha pelo menos uma vez. Ou você pode essencialmente mudar o valor do atributo “elevationAction”.

No caso acima, o valor está definido como “Password” o que significa que você tem que fornecer uma senha. Os outros valores permitidos são Block e Allow.

Se você definir como Block, a execução do seu código será bloqueada, mesmo que forneça uma senha valida. Você vai receber a seguinte mensagem:

 

O que você deve usar nesse caso é Allow. Com isso você conseguirá rodar os scripts quantas vezes quiser sem precisar fornecer a sua senha a cada vez.