Blog4Umbraco Post Date

As the first two posts for this blog were more business focused than technology focused, I wanted to do a little digging for this post and get into some code.

"Fortunately" I came across a need for my blog which, if the Umbraco Forum is any indication, has vexed couple of other people. That is the need to have an alternate Post Date other than the Created Date. This is more than just changing the date, but it is also a matter of changing the structure of the date folders within which it resides.

Background

This blog uses the Blog4Umbraco package put together by the estimable Tim Geyssens. It is MIT licensed Open Source and you can download the source from a link on the Blog4Umbraco project in Codeplex.

One useful part of the package is the feature which automatically creates date folders for a blog post giving one the handy /year/month/day/postname path. It does this by using the Umbraco event model to capture the New Event which is fired when a new document is created. Within the event handler, it checks to see if the post is currently in a Date Folder, and if not, it creates a folder structure for the /year/month/day as necessary (based on the CreateDate at the time the New Document was created) and moves the post there. In addition, many of the XSLT macros for ordering and rolling up posts rely on the CreateDate to determine the order.

These facts have the following ramifications:

  1. Document path is set at the time of creation and is based on the CreateDate, so your path will be based on that, regardless of when you publish it.
  2. Changing the CreateDate by itself will not affect the path, since the path is set when the document is first created and the document must be created before you can reference the createdate in code in order to change it.
    1. This is why importing blogs will often run into this issue,
  3. Changing the path but not changing the CreateDate will cause your documents to sometimes be ordered in a different order than your published dates if the default XSLT files are used.

Requirements

So to address the shortfalls of using the CreateDate I want to create an alternate Post Date which will be used for Blog dating and ordering and which will determine the folder path to the Blog.

To create an alternate post date I have to handle not only the date structure, but also the XSLT which displays that date as the Date Posted instead of the the CreateDate and also orders the posts based on that date. In addition, it should pre-populate the new field with the create date originally so that the XSLT has a value to work with. Finally, to have an optimal solution, it should only attempt to move the blog when necessary.

Solution

The first part of this solution and the key to the rest of it is to create a new property on the Blog Post Document Type called whatever you want (I called it Post Date) but with an alias of PostDate.  Use the DatePicker DataType for convenience.

PostDateEx

Once we have this in place, we'll need to do a few things to make it useful.  First we'll want to populate it automatically with the Create Date upon generating a new post.  Since we will later be updating our XSLT to sort our entries using this field, we want to make sure it has a value.  Second, we'll want to move the post to the appropriate folder structure based upon this new Post Date, but only as when it changes.

For both of these requirements, the handy Document Events are the way to go.  Umbraco Events allow you to listen for actions Umbraco is taking like creating new pages.  Then you can run your custom code to interact with Umbraco while this is happening.  (For those of you experienced in .Net Event Handlers, that is what they are).  The Umbraco Wiki has some pages on how to make use of these events, so I won't go into great detail, but it is really easy if you have any .Net experience.  [If you just want to use the dll that I've coded, I've included it with the class file at the bottom of this post.  Just drop it in your bin directory and Umbraco will know it is there.  Usual caveats of "No Guarantees...'' and "Do so at your own risk".]

Auto-populate the Post Date

The first event we want to use if the Document.New event.  This will allow us to autopopulate our new Post Date field with the Create Date.

void Document_New(Document sender, umbraco.cms.businesslogic.NewEventArgs e)
{
    if (sender.ContentType.Alias == "BlogPost")
     {
       if (sender.getProperty("PostDate") != null)
         {
               sender.getProperty("PostDate").Value = sender.CreateDateTime.Date;
         }
     }
}

Notice the first If-statement.  You will see this critical If-statement in many examples of event handling in Umbraco.  It is important to understand that Umbraco fires an event whenever an appropriate action occurs regardless of whether it is germane to what you are doing.  In this case the Document.New event will be fired every time a new document is created, regardless of whether it is a Blog Post or a News Article or some other new page on your site.  The sender.ContentType.Alias property is a good way to make sure that you are only taking further action if it is related to what you are trying to accomplish.  If you are not sure of the appropriate Document Alias, you can find it by going to the Settings Section of your Umbraco Admin, expand the Document Types folder and click on the document type you are trying to handle.  You will see the Alias (and be able to update it) on the screen that is loaded.

Document Alias

Move the Document to the right Folder path

Ok, now we've populated our PostDate field.  How do we move our post to the correct folder path?  Also, just as importantly, how do we avoid trying to move it when we don't need to?

Fortunately, for moving the folder, the Blog4Umbraco code shows us how it is being placed in the folder path in the first place.  We just have a few tweaks for this part.  First, we want to use the Document.BeforePublish event and not the new event.

void Document_BeforePublish(Document sender, umbraco.cms.businesslogic.PublishEventArgs e)
{
//... Our code will go here.
}

Next, we only want to run the code if we need to.  So we'll check for the Post Date and make sure it has changed since the last time the page was published.

//Don't forget that above this is:
//if (sender.ContentType.Alias == "BlogPost")
if (sender.getProperty("PostDate") != null) //If no post date, skip
{
if (sender.Parent != null) //If top of tree, something is wrong. Skip.
{
try
{
DocumentVersionList[] postVersions = sender.GetVersions();
bool _versionCheck = true;
DateTime postDate;
postDate = System.Convert.ToDateTime(sender.getProperty("PostDate").Value);
if (postVersions.Length > 1) //If it has been published, check post date info
{
//Length -1 is current version Length -2 is past version (if it exists)
Guid previousVersion = postVersions[postVersions.Length - 2].Version;
Document doc = new Document(sender.Id, previousVersion);
DateTime previousPostDate = System.Convert.ToDateTime(doc.getProperty("PostDate").Value);
_versionCheck = (postDate != previousPostDate);
}
if (_versionCheck) //Only do the date folder movement if the PostDate is changed or is new Post.
{
//... More Code
}
}
}
}

Next, we want to use the post date and not the created date.

string[] strArray = { postDate.Year.ToString(), postDate.Month.ToString(), postDate.Day.ToString() };

Next, we are likely in a Date Folder, so well need to find the top of the blog so that we can create the correct Date Folders in the correct places.

if (strArray.Length == 3)
{
Node topBlogLevel = new Node(sender.Parent.Id);
//Traverse up the tree to Find the Blog Node since we are likely in a Date Folder path
while (topBlogLevel != null && topBlogLevel.NodeTypeAlias != "Blog")
{
if (topBlogLevel.Parent != null)
{
topBlogLevel = new Node(topBlogLevel.Parent.Id);
}
else
{
topBlogLevel = null;
}
}
if (topBlogLevel != null)
{
//Create Appropriate Date Folders
}
}

Finally, check for and create the post folders similar to the way the Blog4Umbraco does it when first creating a post.  Given that my code is very similar to what Tim did [read: brazen code reuse] I won't post it here, but as I mentioned, I've included that class file, modified XSLT, modified BlogPost.master and dll at the bottom of this post.

Final Comments

This is one solution to moving Blog Posts to new Date Folder paths.  Some things to understand before you implement this solution.

  1. Although this should work for importation, it hasn't been tested.  The biggest issue, in my opinion, will be threading.  If this is being called asynchronously, it is theoretically possible for duplicate folders to be created since a second thread may find a date folder isn't there and try to create it while a first thread is in the process of doing the same.  Although it would slow things down a little, some Mutex calls around the Folder Discovery part may be necessary.
  2. Use at your own risk.  This was only tested against my personal install(s) of blog4Umbraco 2.0.26.  Additionally, it modifies the xslt and BlogPost.master so future updates to the blog engine may overwrite these changes.  I'm going to submit this as a patch to the codeplex project, so it may make it in.  If it does, you may have to remove the homemade version so it doesn't try to do this twice.

BTW, I started this blog post March 30th.

You can download the code and binary here.

12 comments for “Blog4Umbraco Post Date”

  1. Posted Saturday, April 10, 2010 at 3:23:04 AM

    Hello, this is a great thing and something I have come across myself as a problem and has put me off moving to blog4umbraco due to importing alot of old articles.

    I highly suggest that you submit this as a patch to the blog4umbraco codebase, so its part of the package by default. This will then be a step closer to making it a more usable experience.

    Warren :)

  2. Posted Saturday, April 10, 2010 at 5:21:07 AM

    Nicely done! Would be great to have this included by default. Hit me with your codeplex username and I'll add you to the project.

  3. Posted Monday, April 12, 2010 at 12:05:42 PM

    @Warren - Thanks, I've already submitted it.
    @Tim - Thanks. I would love to see this functionality in the basic package as well. I see that you found me on Codeplex before I had a chance to tell you. :) I'll contact you about some other thoughts as well.

  4. Posted Friday, June 25, 2010 at 6:01:32 AM

    Hi Webangelo,

    I notice in Codeplex commits that http://blog4umbraco.codeplex.com/SourceControl/list/changesets your latest changes are still pending. Do you have ETA for making final fix? I would love to see this feature so I can import old posts.

  5. Posted Thursday, July 01, 2010 at 12:52:18 PM

    Hi J-P.

    I'll follow up with Tim and let you know what I find out.

  6. Posted Tuesday, June 07, 2011 at 4:26:07 AM

    meizitang botanical slimming soft gel for sale
    1.Meizitang zisu slimming pill meizitang for sale
    Lose 20-30 lbs per month 100% herbal and safe
    350mg x 30 capsules /box,

    2. Meizitang strong version bottle
    "MSV" on pills with laser , 650mg*36 pills

    3. Meizitang New Version Meizitang slimming tablets
    36 mzt soft gel for sale cheap meizitang

    4. Meizitang old version weight loss
    36 soft gel, meizitang slimming gel

    5. Meizitang botanical slimming (Blue Capsule)
    Weight loss 30 Ibs monthly.Meizitang OEM
    http://yemade.com

  7. Posted Wednesday, June 08, 2011 at 4:01:20 AM

    Maxman 40% Sex Enhancer Feature:
    10 minutes in operation persist 168 hours
    Enlarge your penis in Width and Length
    Stronger and harder erections
    maxman 40% Give you more intense orgasms.

    Maxman Usage:
    8 capsules total, 1 maxman pill each time; Take it about 10-30 minutes before sex life.

    Maxman 40% Note:
    1. Cant be impatient for quick result and overtake this product.
    2. Drink some cool water if you suffer from frequent erection or too long erection.
    3. Don't take more than 1 maxman pill within 24 hours.

    Appliable to the crowd:
    1.Man who can not erection long enough.
    2. Men who have difficulty all the time or just some of the time.
    3. Man who can not get or keep a hard, erect penis suitable for sexual activity.

    Maxman 40% Standard:
    GMP Manufacture Standard

    Maxman 40% Valid Period:
    24 months

    Maxman 40% Storage:
    Place the maxman Sex Enhancer sex pill in airproof, shady and dry conditions. Keep out of the reach of children

    Payment:
    Western Union , Money Gram , TT, L/C, paypal

    Delivery time:
    We shipped maxman products by EMS. It only takes 6~7days to USA, Australia, Canada and UK.
    or other countries.

    Conclusion: the maxman sex products are so far the most effective and strongest sexual healthcare products for men in the world. Which can quickly enhance men’s sexual capability.
    http://www.poerkan.com

  8. Posted Wednesday, August 10, 2011 at 3:45:40 AM

    I was interested know about it.

  9. Posted Friday, October 14, 2011 at 4:28:22 AM

    Hello, this is my first time i visit here. I found so many interesting in your blog especially on how to determine the topic. keep up the good work.

  10. Posted Wednesday, October 26, 2011 at 4:05:19 AM

    Great post! Did this ever make it in to the package?

  11. Posted Tuesday, December 13, 2011 at 7:03:26 PM

    I love your blog.. very nice colors & theme. Did you create this website yourself or did you hire someone to do it for you? Plz answer back as I'm looking to create my own blog and would like to know where u got this from. thank you

  12. Posted Tuesday, January 03, 2012 at 9:51:29 AM

    Good day! I could have sworn I've been to this website before but after checking through some of the post I realized it's new to me. Anyways, I'm definitely happy I found it and I'll be bookmarking and checking back frequently!

Post a comment