Nibble

Archive for the 'tip' Category


Thoughts,tips for creating umbraco packages 4

I’ve created my share of umbraco packages and thought I’d try to share some tips/insights.

Creating packages is easy, the built-in package creator makes it super simple and with package actions you can perform additional common tasks (like updating the xsltextensions) without having to write a single line of code.

It really takes a minimal effort to package something up that you made, even if it’s very project specific it should be possible to isolate the functionality and package it up.

Dare to share

Even a simple package can be a great help, so don’t hesitate and share

Naming

To avoid conflicts and overwriting other existing items when installing a package, make sure you have unique and meaningful names

  • Assemblies

Starting these with your name or company name followed by a project name should be enough to make them unique
FE: Nibble.Umb.Poll

  • Stylesheets, Scripts, Document types, Templates, XSLT files, Macros

A unique and meaningful name that links them back to the package, so it easy to see that they are part of a package
FE: not style.css but starrating.css
not list.xslt but bloglistposts.xslt       

  • Usercontrols

placing these in a new unique folder inside the /usercontrols folder makes it easy to see that they are part of a package
FE: /usercontrols/Nibble.Umb.Poll/poll.ascx

  • Config files

place these in the /config folder (again, with a unique and meaningful name)

Installation

Package are really easy to install but in some cases the package installation might fail. So it’s always great to provide some manual installation instructions, just in case.

Think ahead

You might have created a package with a simple site in mind, but don’t forget they can/will also be used on multilingual sites, site running a different database engine. Or in case it’s a datatype, will be used with Canvas, autoform, doc2form. It’s a great plus if this is taken into account.

What doesn’t work

If the package only works with a certain umbraco version and up or if it only works on sql server, don’t forget to mention this to avoid that people install it on non supported installations.

 

I’ve also added this post to the wiki on our.umbraco.org, if you have anything to add/change (or correct my bad spelling) please do so .

Only log in umbraco members when they have been approved 14

A common thing when dealing with members on your site is that they need to be approved after registration before they can access the protected area on your site.

This post describes a simple way of doing that.

On the umbraco member type I have a True/false property with the alias active. If this is set to true on the member he is an ‘active’ member and is allowed to log in.

activeproperty

 

The only thing that is needed is to override the ValidateUser method of the UmbracoMembershipProvider. So make a custom class, inherit from umbraco.providers.members.UmbracoMembershipProvider and override the method (make sure to reference umbraco.providers).

Instead of just checking if there is a member with the supplied loginname and password we’ll add some extra code that will check if the member has his active property set to true. If that is the case we return true, in all other cases we return false.

 

namespace Nibble
{
    public class CustomMemberShipProvider : umbraco.providers.members.UmbracoMembershipProvider
    {
        public override bool ValidateUser(string username, string password)
        {
            umbraco.cms.businesslogic.member.Member m =
                umbraco.cms.businesslogic.member.Member.GetMemberFromLoginNameAndPassword(
                username, EncodePassword(password));
 
            if (m == null)
            {
                return false;
            }
            else
            {
                try
                {
                    if (m.getProperty(“active”).Value.ToString() == “1″)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
 
                }
                catch
                {
                    return false;
                }
             
            }
            return (m != null);
        }
    }
}

 

Final step is to modify the web.config so that our custom membership provider is used instead of the default umbraco one. So Just change the type attribute on the umbraco membership provider to the type of the custom membership provider.

<add name=”UmbracoMembershipProvider” type=”Nibble.CustomMemberShipProvider”
 enablePasswordRetrieval=”false” enablePasswordReset=”false” requiresQuestionAndAnswer=”false”
 defaultMemberTypeAlias=”CobraMember” passwordFormat=”Hashed” />

 

That’s it, now the asp:login control will only login the member if he has his active property set to true.

Fetching the nodeid in a custom datatype 2

Just a quick tip following the custom datatypes posts (Creating custom umbraco datatypes , Storing parseable xml data in a datatype ).

When creating a datatype you might at some point need to have the current document’s nodeid. Like if you want to insert some extra data in a custom table.

Since the datatypes are also used by autoform/doc2form , liveediting and not only in the umbraco backend the best approach is to fetch it like this:

((umbraco.cms.businesslogic.datatype.DefaultData)_data).NodeId

Storing parseable xml data in a datatype 6

As a follow up on the creating custom umbraco datatypes post I’ll show how to store parseable xml data in a datatype.

By default all propertry values get saved inside a cdata section(in the /data/umbraco.config file, wich has all published content).

Like in this example, a property with the alias test will look like this.

<data alias=”test”><![CDATA[1051;1052;1054]]></data>

But in some cases you would want to override this behavior, especially when you want to store xlm data.

Like the related links datatype in umbraco v4. This will store it’s links as child nodes of the data node.

<data alias=”links”>
        <links>
          <link title=”Same page” link=”http://www.google.com” type=”external” newwindow=”1″ />
          <link title=”Other page” link=”1051″ type=”internal” newwindow=”0″ />
        </links>
</data>

To do this the first step is to create a new class that inherits from umbraco.cms.businesslogic.datatype.DefaultData and overrides the ToXMl method.

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
 
namespace umbraco.editorControls.relatedlinks
{
    public class RelatedLinksData : umbraco.cms.businesslogic.datatype.DefaultData
    {
        public RelatedLinksData(umbraco.cms.businesslogic.datatype.BaseDataType DataType) : base(DataType) { }
 
        public override System.Xml.XmlNode ToXMl(System.Xml.XmlDocument data)
        {
            if (this.Value != null) {
                XmlDocument xd = new XmlDocument();
                xd.LoadXml(this.Value.ToString());
                return data.ImportNode(xd.DocumentElement, true);
            } else {
                return base.ToXMl(data);
            }
        }
 
    }
}

 

Final step is to alter the class that implements the umbraco.interfaces.IDataType interface (the one with the guid) so that the new class is used instead of the default one. So just change

public override umbraco.interfaces.IData Data
        {
            get
            {
                if (_baseData == null)
                    _baseData = new umbraco.cms.businesslogic.datatype.DefaultData(this);
                return _baseData;
            }
        }

   

To (depending on how the class is named, in this case it’s RelatedLinksData)

public override umbraco.interfaces.IData Data
        {
            get
            {
                if (_baseData == null)
                    _baseData = new RelatedLinksData(this);
                return _baseData;
            }
        }

Converting Linebreaks 3

When using the textbox multiple datatype in umbraco you might want to convert the linebreaks into html <br> tags. This can be done just by checking a checkbox in the insert umbraco field dialog when inserting a field on your template. Just look for the convert linebreaks checkbox.

image

 

image 

 

In xslt you can also do this by using the umbraco library method umbraco.library.ReplaceLineBreaks(System.String)

So that would like a this:

<xsl:value-of select=”umbraco.library:ReplaceLineBreaks(data [@alias = ‘youralias’])”/>

XSLT previous,next example 10

Say you have a structure like this on your site.

xslt

Multiple content items of the same documenttype, like news items. And you want to display a previous and a next link on those news items.

This can be done with some xslt. Here is an example:

<?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:template match=”/”>
 
<!– The fun starts here –>
 
<xsl:for-each select=”$currentPage/ancestor-or-self::node [@nodeTypeAlias = ‘NewsPage’]/node”>
 
<xsl:if test=”$currentPage/@id = current()/@id”>
 
 <xsl:call-template name=”prevnext”>
    <xsl:with-param name=”count” select=”count($currentPage/ancestor-or-self::node [@nodeTypeAlias = ‘NewsPage’]/node)”/>
    <xsl:with-param name=”itemindex” select=”position()”/>
  </xsl:call-template>
</xsl:if>
 
</xsl:for-each>
 
</xsl:template>
 
<xsl:template name=”prevnext” >
<xsl:param name=”count” />
<xsl:param name=”itemindex” />
 
<xsl:if test=”$itemindex > 1″>
<a href=”{umbraco.library:NiceUrl($currentPage/ancestor-or-self::node [@nodeTypeAlias = ‘NewsPage’]/node[$itemindex-1]/@id)}”>
Previous</a>
</xsl:if>
 
<xsl:if test=”$itemindex &lt; $count”>
<a href=”{umbraco.library:NiceUrl($currentPage/ancestor-or-self::node [@nodeTypeAlias = ‘NewsPage’]/node[$itemindex +1]/@id)}”>
Next </a>
</xsl:if>
 
</xsl:template>
 
</xsl:stylesheet>

The Key is to know how many nodes(newsitems) there are and what the position of the current node is (first, second, .. last) because you don’t need to display a previous link if it’s the first item or a next link if it’s the last.

UPDATE:

Petr Snobelt mailed me the following snippet, which shows another technique (no for-each loop, so should be faster)

<xsl:if test=”count($currentPage/preceding-sibling::node) != 0″>
previous
<a href=”{umbraco.library:NiceUrl($currentPage/preceding-sibling::node[1]/@id)}”>
 <xsl:value-of select=”$currentPage/preceding-sibling::node[1]/@nodeName”/>
</a>
<br />
</xsl:if>
 
<xsl:if test=”count($currentPage/following-sibling::node) != 0″>
next
<a href=”{umbraco.library:NiceUrl($currentPage/following-sibling::node[1]/@id)}”>
 <xsl:value-of select=”$currentPage/following-sibling::node[1]/@nodeName”/>
</a>
</xsl:if>

Why Umbraco rocks - alternative templates 9

The main building blocks of umbraco are as you know document types and templates. When creating a document types the umbraco interface will give you the options to also create a templates that is then setup as the default template on that document type. If you open up the details of a document types you’ll be able to see the ‘allowed templates’ part on the info tab.

image

Document types aren’t limited to 1 template and this is great! You can easily swith to an ‘alt template’ by simply editing the url of your page.

So if you would have a homepage.aspx and you want to apply templatex on it you can do this by changing the url to

homepage/templatex.aspx

another option is this

homepage.aspx?alttemplate=templatex

In the beginning I didn’t use alternative templates that much but it’s a great way to keep your content section clean.

For example an email to a friend page, instead of making this a new documenttype and adding it to the content en then passing the id of the page you want to email…

You can simply add an email to a friend template and call it up as an alternative template, that way you won’t need to pass the nodeid because you are still on the same node !

Adding a language selector to your multilingual umbraco site 14

Create mutlilingual sites with umbraco, there are several approaches in doing this, the one I use the most is to have multiple ‘top level’ nodes (I’ll make a screencast of this in a future post). So for each language you would have a top level node.

The content tree would look like this:

languageselectorcontent

I would like to add a language selector on the site, a dropdown with all languages that will redirect to the selected langauge homepage. How to do this ?

languageselector

I’ll first add a new property to the top level node document type. This will store the text that is displayed in the dropdown.

languageselectordocumenttype

Next step is to create a new xslt file (with 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:template match=”/”>
<form>
<select name=”langselection” onchange=”loadPage(this.form.elements[0])” target=”_parent._top” >
<option selected=”selected”>– Please select –</option>
 
  <xsl:for-each select=”$currentPage/ancestor::root/node”>
         
         <option value=”{umbraco.library:NiceUrl(@id)}”><xsl:value-of select=”data [@alias = ‘language’]”/></option>      
    
  </xsl:for-each>
</select>
</form>
 
</xsl:template>
 
</xsl:stylesheet>

This will output the html code for the dropdown. The most important part is the for-each loop, wich will loop all top level nodes, add the url of the top level node as a value of the dropdown option and add the content of the language property as the displayed text of the drop down option.

Now you can add the macro to your template, but you’ll also need to add a little javascript.

<script language=“JavaScript”>
 
function loadPage(list) {
 
  location.href=list.options[list.selectedIndex].value
 
}
 
</script>

Creating packages for umbraco, usercontrol that fires as last step of installation 2

Thanks to Per’s packager (which will be integrated in v4) creating packages for umbraco is a very simple thing. The only part that can get a little tricky is if you need to update the database, or one of the config files.

The way to do this is to create a custom usercontrol, and this usercontrol gets fired at the last step of the package installation (you need to set this up in the package.xml file). I’ve created several packages so I thought I would just show the way I did these things.

 

Executing a SQL statement ( to create new tables )

StreamReader reader = new StreamReader(base.Server.MapPath(“/umbraco/plugins/nibble/demo/installer/demo.sql”));
string sqlStatement = reader.ReadToEnd();
reader.Close();
SqlHelper.ExecuteNonQuery(GlobalSettings.DbDSN, CommandType.Text, sqlStatement);

In this sample the statement is stored in a .sql file, then it is just read in and executed.

 

Updating xsltExtensions.config ( for xslt extensions )

XmlDocument document = new XmlDocument();
document.Load(base.Server.MapPath(“/config/xsltExtensions.config”));
XmlNode node = document.SelectSingleNode(“/XsltExtensions”);
if (node.SelectNodes(“/ext [@assembly = ‘/bin/Jesper.GoogleMaps’]”).Count == 0)
{
    XmlNode newChild = document.CreateElement(“ext”);
    XmlAttribute attribute = document.CreateAttribute(“assembly”);
    attribute.Value = “/bin/Jesper.GoogleMaps”;
    newChild.Attributes.Append(attribute);
    XmlAttribute attribute2 = document.CreateAttribute(“type”);
    attribute2.Value = “Jesper.GoogleMaps.Library”;
    newChild.Attributes.Append(attribute2);
    XmlAttribute attribute3 = document.CreateAttribute(“alias”);
    attribute3.Value = “GoogleMaps.Library”;
    newChild.Attributes.Append(attribute3);
    node.AppendChild(newChild);
    document.Save(base.Server.MapPath(“/config/xsltExtensions.config”));
}

this sample will add

<ext assembly=”/bin/Jesper.GoogleMaps” type=”Jesper.GoogleMaps.Library” alias=”GoogleMaps.Library” />

to the /config/xsltExtensions.config file

 

Updating restExtensions.config ( for base )

XmlDocument document = new XmlDocument();            
document.Load(Server.MapPath(“/config/”) + “restExtensions.config”);
XmlNode newChild = document.CreateElement(“ext”);
 
 
XmlAttribute AtAssembly = document.CreateAttribute(“assembly”);
AtAssembly.Value = “/bin/xtraUmbracoStarRating”;
newChild.Attributes.Append(AtAssembly);
 
XmlAttribute atType = document.CreateAttribute(“type”);
atType.Value = “xtraUmbracoStarRating.StarRating”;
newChild.Attributes.Append(atType);
 
XmlAttribute atAlias = document.CreateAttribute(“alias”);
atAlias.Value = “StarRating”;
newChild.Attributes.Append(atAlias);
 
XmlNode permissionNode = document.CreateElement(“permission”);
newChild.AppendChild(permissionNode);
 
XmlAttribute atMethod = document.CreateAttribute(“method”);
atMethod.Value = “update”;
permissionNode.Attributes.Append(atMethod);
 
XmlAttribute atAllowAll = document.CreateAttribute(“allowAll”);
atAllowAll.Value = “true”;
permissionNode.Attributes.Append(atAllowAll);
 
document.DocumentElement.AppendChild(newChild);
 
document.Save(Server.MapPath(“/config/”) + “restExtensions.config”);

this sample will add

<ext assembly=”/bin/xtraUmbracoStarRating” type=”xtraUmbracoStarRating.StarRating” alias=”StarRating”>
    <permission method=”update” allowAll=”true” />
</ext>

to the /config/restExtensions.config file

 

Updating dashboard.config ( to add usercontrols on the dashboard )

XmlDocument document = new XmlDocument();
document.Load(base.Server.MapPath(“/config/Dashboard.config”));
XmlNode node = document.SelectSingleNode(“/dashBoard”);
 
XmlNode sectionChild = document.CreateElement(“section”);
XmlNode areasChild = document.CreateElement(“areas”);
XmlNode areaChild = document.CreateElement(“area”);
 
areaChild.InnerText = “developer”;
 
XmlNode tabChild = document.CreateElement(“tab”);
 
XmlAttribute attribute = document.CreateAttribute(“caption”);
attribute.Value = “Nibble FX”;
tabChild.Attributes.Append(attribute);
 
XmlNode controlChild = document.CreateElement(“control”);
 
controlChild.InnerText = “/usercontrols/Nibble/NibbleFX.ascx”;
 
               
tabChild.AppendChild(controlChild);
areasChild.AppendChild(areaChild);
sectionChild.AppendChild(areasChild);
sectionChild.AppendChild(tabChild);
node.AppendChild(sectionChild);
document.Save(base.Server.MapPath(“/config/Dashboard.config”));

this sample will add

  <section>
    <areas>
      <area>developer</area>
    </areas>
    <tab caption=”Nibble FX”>
      <control>/usercontrols/Nibble/NibbleFX.ascx</control>
    </tab>
  </section>

to the /config/dashboard.config file

/Config/Dashboard.config 4

Just posted this on the forum and I thought I could do a quick post about the umbraco dashboard.config file.

When you log in the the umbraco backend or when you enter a section, the right side of the umbrao backend will be empty

image

You can fill up these ‘dashboards’ with tab pages that contain usercontrols.

How do you do this ? You will have to edit the /config/dashboard.config file.

Default the dashboard.config file looks like this:

<?xml version=”1.0″ encoding=”utf-8″ ?> 
<dashBoard>
<!–
    <section>
    <areas>
        <area>default</area>
        <area>content</area>
    </areas>
    <tab caption=”Last Edits”>
        <control>/usercontrols/dashboard/latestEdits.ascx</control>
    </tab>
    <tab caption=”Latest Items”>
        <control>/usercontrols/dashboard/newestItems.ascx</control>
    </tab>
    <tab caption=”Create blog post”>
        <control>/usercontrols/umbracoBlog/dashboardBlogPostCreate.ascx</control>
    </tab>
</section>
–>
</dashBoard>

 

So to add a usercontrol to th content area we should add this:

<?xml version=”1.0″ encoding=”utf-8″ ?> 
<dashBoard>
 
    <section>
    <areas>
        <area>content</area>
    </areas>
 
    <tab caption=”Last Edits”>
        <control>/usercontrols/mycustomusercontrol.ascx</control>
    </tab>
 
</section>
</dashBoard>

Next Page »