Saturday, February 28, 2009

Intergrate Yet Another Forum 1.9.3RC2 with Umbraco 4

Since Umbraco doesn't have a integrated forum package yet I tried to integrate the latest version of YAF.

Here are the steps that I took and the issues that I encountered.

Preparing Umbraco

  1. Download and install Umbraco4 with Runway to keep it simple
  2. In Umbraco you create new documenttype called Forum and a matching template
  3. Add properties to this documenttype. I only added a title property for this tutorial.
  4. Add the forum documenttype to the allowed childnode types of the Runway homepage
  5. Change the Forum template so it uses the Runway master template
  6. Create a forum page and publish it.
  7. Go to the member section and create 2 Membergroups : Registered Users and Adminstrators
  8. Create a Membertype Registered user
  9. Create a user of the type Registered user and add it to the Admistrators group
  10. Modify the master template by adding code snippet 1 to the Runwaymaster template just before the ContentPlaceHolder
  11. Go to your website and login using the user you just created and confirm that it works

Preparing YAF

  1. Download and unzip YAF to a folder YAF under your Umbraco root
  2. Backup your Umbraco web.config
  3. Copy all the file is in the YAF bin folder to the Umbraco bin folder. If you got to your Umbraco backend UI now you see that it stops working. We solve that in the next step
  4. Open up the Umbraco web.config and add code snippet 2 to it at the bottom before the closing configuration tag. Now the Umbraco backend UI should work again. If not check the version of the AjaxToolkit.dll from the Umbraco zip file and the YAF zip file and change the version numbers in the code snippet
  5. Copy the App_Code folder from the YAF directory to the Umbraco App_Code folder
  6. UPDATE 23/03/2009 : Open up the file App_Code/YAF/Forum.cs and add this.Init += new EventHandler( Forum_Init );  to the constructor (public Forum()). Also add code snippet 9 to this file.
  7. Next open up the web.config and copy/paste code snippet 3 in to the appSettings section. These are the settings from the YAF app.config file with the needed modifications. If you run the forum page in a subdirectory like <yourwebsite>/blabla/forum.aspx you will have to change the baseUrl property to match this directory.
  8. Modify the appSetting umbracoReservedPaths to <add key="umbracoReservedPaths" value="/umbraco,/install/,/yaf/" />
  9. Add code snippet 4 to the Umbraco web.config in the configuration section. Modify the connectionstring so it connects to your YAF database. In this case I will use the Umbraco database.
  10. Add <add name="YafInitModule" type="YAF.Classes.Base.YafInitModule, YAF.Classes.Base"/> to HttpModules section of your Umbraco web.config
  11. Replace the pages section in the Umbraco web.config with code snippet 5
  12. Add code snippet 6 to the Umbraco web.config in the system.web section
  13. UPDATE 23/03/2009 : Add code snippet 8 to the file config/UrlRewriting.config
  14. Delete the bin and App_Code folder from the YAF directory

Install YAF

  1. Open up a browers and call <yourwebsite>/yaf/install/default.aspx
  2. In the first step enter the a password
  3. In step 2 install full text search if your database supports it
  4. In step 3 configure your forum with a existing user. Use the user we created during the setup of umbraco.
  5. In step 4 click finish. This will redirect to the homepage of your website

Using YAF in umbraco

  1. In Umbraco open up your forum masterpage and add <yaf:Forum id="yafForum" runat="server"/> between the asp:Content tags
  2. If you visit your forum page on the website you will see a ugly error. This is caused by a "bug????" in the Umbraco Membership Provider. To override this error create a file called YAFUmbracoMembership.cs in the App_Code folder of Umbraco. Copy code snippet 7 into this file.
  3. Change your Umbraco web.config so that the membership Provider uses Dawoe.Providers.YAFUmbracoMembership
  4. Change the Umbraco web.config so that profile is enabled.
  5. Open up the forum page again and voila !!! YAF integrated in Umbraco. Try to login and you will see that it works.
  6. Also try to create a new user in umbraco and Login in with that one.

Known issues

  1. Registering through the forum doesn't work. No workaround yet. Disable it for now in the YAF hostsettings.

If somebody finds other issues and/or solutions please report them and I'll update this post.

Code snippets

Code snippet 1 :

<asp:LoginView id="loginView" runat="server">
    <AnonymousTemplate>
        <asp:Login id="login" runat="server" />
    </AnonymousTemplate>
    <LoggedInTemplate>
        <asp:LoginStatus id="loginStatus" runat="server"/>
    </LoggedInTemplate>
</asp:LoginView>

Code snippet 2 :

 <!-- Ajaxtoolkit bindings -->
<runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
        <dependentAssembly>
            <assemblyIdentity name="AjaxControlToolkit" publicKeyToken="28f01b0e84b6d53e"/>
            <publisherPolicy apply="no"/>
            <bindingRedirect oldVersion="1.0.10920.32880" newVersion="1.0.20229.26329"/>
        </dependentAssembly>
        <dependentAssembly>
            <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31BF3856AD364E35"/>
            <publisherPolicy apply="no"/>
            <bindingRedirect oldVersion="3.5.0.0" newVersion="1.0.61025.0"/>
        </dependentAssembly>
    </assemblyBinding>
</runtime>

Code snippet 3 :

<add key="configPassword" value="" />
<add key="BoardID" value="1" />
<add key="EnableURLRewriting" value="false" />
<add key="databaseObjectQualifier" value="yaf_" />
<add key="databaseOwner" value="dbo" />
<add key="providerExceptionXML" value="ProviderExceptions.xml" />
<add key="UploadDir" value="~/yaf/upload/" />
<add key="ProviderKeyType" value="System.Int32" /> 
<add key="root" value="/yaf" />  
<add key="BaseUrl" value="~/yaf" />
<add key="BaseUrlOverrideDomain" value="false" />   

Code snippet 4 :

<connectionStrings>
    <add name="yafnet" connectionString="server=.\sqlexpress;database=umbraco;user id=umbracoUser;password=umbraco" />
</connectionStrings>

Code snippet 5 :

<pages validateRequest="false" smartNavigation="false">
    <controls>
        <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
        <add tagPrefix="umbraco" namespace="umbraco.presentation.templateControls" assembly="umbraco" />
        <add tagPrefix="ajaxToolkit" namespace="AjaxControlToolkit" assembly="AjaxControlToolkit"/>
        <add tagPrefix="YAF" namespace="YAF.Classes.UI" assembly="YAF.Classes.UI" />
        <add tagPrefix="YAF" namespace="YAF.Classes.Utils" assembly="YAF.Classes.Utils" />
        <add tagPrefix="YAF" namespace="YAF.Classes.Data" assembly="YAF.Classes.Data" />
        <add tagPrefix="YAF" namespace="YAF.Controls" assembly="YAF.Controls" />
        <add tagPrefix="YAF" namespace="YAF.Controls.Statistics" assembly="YAF.Controls" />                
        <add tagPrefix="YAF" namespace="YAF.Classes" />
        <add tagPrefix="YAF" namespace="YAF"/>
        <add tagPrefix="editor" namespace="YAF.Editor"/>
    </controls>
    <namespaces>
        <add namespace="YAF" />
        <add namespace="YAF.Classes.UI" />
        <add namespace="YAF.Classes.Utils" />
        <add namespace="YAF.Controls" />
        <add namespace="YAF.Classes.Data" />
    </namespaces>
</pages>

Code snippet 6 :

<profile enabled="false" defaultProvider="YafProfileProvider" inherits="YAF.Classes.Utils.YafUserProfile">
    <providers>
        <clear/>
        <add connectionStringName="yafnet" applicationName="YetAnotherForum" name="YafProfileProvider" type="YAF.Providers.Profile.YafProfileProvider"/>
    </providers>
</profile>

Code snippet 7 :

namespace Dawoe.Providers
{
    public class YAFUmbracoMembership : umbraco.providers.members.UmbracoMembershipProvider
    {
        public override string ApplicationName
        {
            get
            {
                return base.ApplicationName;
            }
            set
            {
                // Do nothing because umbraco doesn't allow empty applicationnames or applicationnames with a lenght greater than 0
            }
        }
    }
}

Code snippet 8 :

<add name="YafFramehelperRewrite" virtualUrl="framehelper.aspx(.*)" rewriteUrlParameter="ExcludeFromClientQueryString" destinationUrl="/yaf/framehelper.aspx?$1" ignoreCase="true" />
<add name="YafAdvancedRewrite" virtualUrl="advanced.aspx(.*)" rewriteUrlParameter="ExcludeFromClientQueryString" destinationUrl="/yaf/advanced.aspx?$1" ignoreCase="true" />
<add name="YafErrorRewrite" virtualUrl="error.aspx(.*)" rewriteUrlParameter="ExcludeFromClientQueryString" destinationUrl="/yaf/error.aspx?$1" ignoreCase="true" />
<add name="YafResourceRewrite" virtualUrl="resource.ashx(.*)" rewriteUrlParameter="ExcludeFromClientQueryString" destinationUrl="/yaf/resource.ashx?$1" ignoreCase="true" />
<add name="YafRewrite" virtualUrl="/yaf/forum.aspx(.*)" rewriteUrlParameter="ExcludeFromClientQueryString" destinationUrl="/forum.aspx?$1" ignoreCase="true" />

Code snippet 9 :

private void Forum_Init(object sender, EventArgs e)
{
    try {
        ((umbraco.UmbracoDefault)this.Page).ValidateRequest = false;
        }
    catch {
        // catch error when page isn't called with umbraco master page
        }
}

Monday, August 11, 2008

Vote for Umbraco

Go vote for Umbraco at the Packt Pub CMS Awards '08

Thursday, April 10, 2008

Macro for HTML encoding fields in templates

In Umbraco when you try to add a field to your template you can UrlEncode it like this :
<?UMBRACO_GETITEM field="MyField" urlEncode="true" />

But you can't do this :
<?UMBRACO_GETITEM field="MyField"  htmlEncode="true" />

I read in this forum thread that a fix for this has been submitted to codeplex but untill it's released I have made a macro to work around this.

First create a XSLT file and call it HTMLEncode and check the box "Create macro"

Then paste the following code in to your macro :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:Stylesheet [ &lt;!ENTITY nbsp "&#x00A0;"> ]>
<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxml="urn:schemas-microsoft-com:xslt"
    xmlns:umbraco.library="urn:umbraco.library"
    exclude-result-prefixes="msxml umbraco.library">


<xsl:output method="xml" omit-xml-declaration="yes"/>

<xsl:param name="currentPage"/>

<xsl:param name="field" select="/macro/field" />

<xsl:template match="/">

<!-- start writing XSLT -->
<xsl:if test="$field">
    <xsl:value-of select="$currentPage/data[@alias=$field]"/>
</xsl:if>
</xsl:template>

</xsl:stylesheet>

Then go to your macro and add a parameter called field of the type propertyTypePicker

In your templates you can now use this macro to htmlencode fields.

I hope you can use it.

Next blog will be about importing node with the webservices API.

Thursday, March 6, 2008

Transforming feeds...one XSLT to rule them all

For a client at my work I needed to built a feed reading module in to their CMS. I created the following XSLT to transform the feeds to the desired HTML. This XSLT can be used for Atom 0.3, Atom 1.0, RSS 0.90, RSS 0.91, RSS 0.92, RSS 1.0 and RSS 2.0.

With some minor tweaks this can be used in Umbraco as well. Here is an example of reading a atom feed in Umbraco.


Here is my XSLT.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:atom3="http://purl.org/atom/ns#"
    xmlns:rss="http://purl.org/rss/1.0/"
    xmlns:rss09="http://my.netscape.com/rdf/simple/0.9/"    
    exclude-result-prefixes="xsl rdf dc rss rss09 atom atom3"
>

<!--
=============================================================================
 XSLT to convert RSS and Atom feeds to desired html
=============================================================================
-->
<xsl:output method="html" omit-xml-declaration="yes" indent="yes"/>

<!--
=============================================================================
Input parameters for displaying maximum items from feed
=============================================================================
-->

<xsl:variable name="maxitems" select="10" />

<xsl:template match="/">
                
    <xsl:element name="ul">    
        <xsl:attribute name="class">rssfeed</xsl:attribute>        
        
        <!-- Atom 1.0 -->
        <xsl:apply-templates select="/atom:feed"/>
        <!-- Atom 0.3 -->
        <xsl:apply-templates select="/atom3:feed"/>
        <!-- RSS 0.91 , 0.92 , 2.0 -->
        <xsl:apply-templates select="rss/channel" />
        <!-- RSS 1.0 -->
        <xsl:if test="rdf:RDF/rss:item">
            <xsl:apply-templates select="rdf:RDF/rss:item[position() &lt; number($maxitems)+1]"/>
        </xsl:if>
        <!-- RSS 0.9 -->
        <xsl:if test="rdf:RDF/rss09:item">
            <xsl:apply-templates select="rdf:RDF/rss09:item[position() &lt; number($maxitems)+1]"/>
        </xsl:if>
        
    </xsl:element>

</xsl:template>


<!--
=============================================================================
 RSS 0.91,0.92,2.0
=============================================================================
-->
<xsl:template match="channel">        
    <xsl:apply-templates select="item[position() &lt; number($maxitems)+1]" />        
</xsl:template>

<xsl:template match="item">       
    <xsl:call-template name="drawlinks">
        <xsl:with-param name="item_link" select="link" />
        <xsl:with-param name="item_title" select="title" />
    </xsl:call-template>
</xsl:template>


<!--
=============================================================================
 RSS 1.0
=============================================================================
-->
<xsl:template match="rss:item">     
     <xsl:call-template name="drawlinks">
        <xsl:with-param name="item_link" select="rss:link" />
        <xsl:with-param name="item_title" select="rss:title" />
    </xsl:call-template>
</xsl:template>

<!--
=============================================================================
 RSS 0.90
=============================================================================
-->
<xsl:template match="rss09:item">    
    <xsl:call-template name="drawlinks">
        <xsl:with-param name="item_link" select="rss09:link" />
        <xsl:with-param name="item_title" select="rss09:title" />
    </xsl:call-template>
</xsl:template>

<!--
=============================================================================
Atom 1.0
=============================================================================
-->
<xsl:template match="/atom:feed">
    <xsl:apply-templates select="atom:entry[position() &lt; number($maxitems)+1]" />
</xsl:template>

<xsl:template match="atom:entry">
    <xsl:call-template name="drawlinks">
        <xsl:with-param name="item_link" select="atom:link/@href" />
        <xsl:with-param name="item_title" select="atom:title" />
    </xsl:call-template>
</xsl:template> 

<!--
=============================================================================
Atom 0.3
=============================================================================
--> 
<xsl:template match="/atom3:feed">    
    <xsl:apply-templates select="atom3:entry[position() &lt; number($maxitems)+1]" />    
</xsl:template>
 
<xsl:template match="atom3:entry">  
    <xsl:call-template name="drawlinks">
        <xsl:with-param name="item_link" select="atom3:link/@href" />
        <xsl:with-param name="item_title" select="atom3:title" />
    </xsl:call-template>
</xsl:template> 

<!--
=============================================================================
Template for making list items from feed items
=============================================================================
-->
<xsl:template name="drawlinks">
    <xsl:param name="item_link" />
    <xsl:param name="item_title" />
    <xsl:element name="li">        
        <xsl:element name="a">
            <xsl:attribute name="href"><xsl:value-of select="$item_link" /></xsl:attribute>
            <xsl:attribute name="target">_blank</xsl:attribute>
            <xsl:attribute name="title"><xsl:value-of select="$item_title" /></xsl:attribute>
            <xsl:value-of select="$item_title" />
        </xsl:element>    
    </xsl:element>
</xsl:template>
</xsl:stylesheet>

If you have issues with this, let me know.

Cheers,

Dave

Monday, February 4, 2008

Sitecore Xpress Personal Developer Edition coming

I found on this blog that Sitecore is releasing a personal edition that's free to use for personal websites.

The site htttp://xpress.sitecore.net will launch on Thursday, February 7, 2008 at 7.30 AM CET. There are also 2 webinars that you can register for. I'll see if I can find the time to watch one of them.

But it's definilaty worth to have a look at.

Monday, January 28, 2008

Adding CSS or JavaScript to your mastertemplate based on documenttype

The way I normally work when making websites is to use several CSS-files and JavaScript-files. So most of the time I have a main.css and general.js file that is included in every page. But when I have pages that needed separate styling or clientside functionality I add for example a news.css and news.js. So I the visitor only has to download these file when needed.

In Umbraco there is no build-in function to append to the <head>-section of your mastertemplate from your childtemplate. To solve this I see several solutions :

  1. Build multiple mastertemplate
  2. Use a macro

Because solution 1 needs a lot of maintenance I decided to build a macro.

How does it work :

You insert this macro in to your mastertemplate. In the macro you decide based on the nodeTypeAlias attribute of the currentPage which CSS-file or JavaScript-file to add.

Here is the XSLT you need

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [
  &amp;lt;!ENTITY nbsp "&#x00A0;">
]>
<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxml="urn:schemas-microsoft-com:xslt"
    xmlns:umbraco.library="urn:umbraco.library"
    exclude-result-prefixes="msxml umbraco.library">


  <xsl:output method="xml" omit-xml-declaration="yes"/>

  <xsl:param name="currentPage"/>

  <xsl:template match="/">

    <xsl:choose>
      <xsl:when test="$currentPage/@nodeTypeAlias = 'News'">
        <xsl:call-template name="css">
          <xsl:with-param name="file">/css/news.css</xsl:with-param>
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$currentPage/@nodeTypeAlias = 'TextPage'">
        <xsl:call-template name="script">
          <xsl:with-param name="file">/scripts/textpage.js</xsl:with-param>
        </xsl:call-template>
      </xsl:when>
    </xsl:choose>

  </xsl:template>

  <xsl:template name="css">
    <xsl:param name="file" />
    <xsl:element name="link">
      <xsl:attribute name="rel">stylesheet</xsl:attribute>
      <xsl:attribute name="type">text/css</xsl:attribute>
      <xsl:attribute name="href">
        <xsl:value-of select="$file"/>
      </xsl:attribute>
    </xsl:element>
  </xsl:template>

  <xsl:template name="script">
    <xsl:param name="file" />
    <!-- to prevent that a self closing script tag is generated we use the xsl:text-->
    <xsl:text disable-output-escaping="yes"><![CDATA[<script language="javascript" type="text/javascript" src="]]></xsl:text>
    <xsl:value-of select="$file"/>
    <xsl:text disable-output-escaping="yes"><![CDATA["></script>]]></xsl:text>
  </xsl:template> 
</xsl:stylesheet>

If you think there is a way to improve this let me know !

Wednesday, January 23, 2008

Testing MySql support for Umbraco

Most recently, new core team member and fellow Belgian Ruben Verborgh, created a data-layer for Umbraco with support for MySql. You can read about it here. I decided to try it out because my current hosting supports MySql and not MS SQL. Everything runs as expected, except for a known bug in the media section. If you try to upload a file you will get a error, but the file gets uploaded, only some properties are not being saved. The MySql support will be officialy released with Umbraco 3.1.

Converting a DotNetNuke site to Umbraco

I recently discovered Umbraco when I was looking for an alternative to DotNetNuke. After playing around with it for a couple of evenings, I decided to convert a site running on DotNetNuke 2.1.2 on a Access database to Umbraco. The first steps I took to get to know Umbraco were :

  1. Install Umbraco as described here
  2. Install the Creative Web Specialist Website package and see how it works
  3. Googled for some XSLT tutorials to brush up my knowledge on it, because Umbraco is extensible through XSLT macro's
  4. Installed a clean Umbraco instance and tried out the screencasts found here.
The following things will have to be done to convert the site :
  1. Create a template for the site
  2. Create a guestbook package using a .NET usercontrol to post messages
  3. Import the guestbook messages from the old site.
  4. Create a news package with archive using a ActionHandler save the news items in a correct subfolder similar to the blog package
  5. Create a picture gallery package using SWFUpload for uploading pictures
  6. Create events package
  7. Create a members section using the MemberControls
  8. Maybe more that I can't think of now
Some extra things I want to do is :
  1. Test the MySQL support recently created by Ruben Verborgh
  2. Create a Data Layer for MS Access or another DB. This is mostly a learning project for the Umbraco source.
I'll keep updating this blog with my progress. Cheers ! Dave