Making A Dynamic Upload Directory


Published on October 7, 2004 at 8:05 PM EST
In the Tutorials category.

http://www.eatdrinksleepmovabletype.com/upload/2005/10/upload-default-thumb.gif

If you use the Upload File feature in Movable Type, you’ve no doubt got a folder full of uploaded files. If you use the default “Local Archive Path” or “Local Site Path” destination, you’ve got a folder full of uploads mixed in with your web pages. I always want to keep my uploaded files separate from all of the web pages just for organization. But now my /uploads/ folder has over 1300 files in it and finding anything is impossible. I needed a better organization method and I didn’t want to have to actively think about it.

2005/04/19 Update: The method has been refined quite a bit with The Easy Way, using JavaScript.

2005/05/10 Update: This method is superceded by better Upload File templates.

Specifying A Default Upload Directory

http://www.eatdrinksleepmovabletype.com/upload/2005/10/upload-value-thumb.gif

Shortly after installing Movable Type I decided I wanted to specify a default upload folder. Modifying the upload.tmpl file (in the tmpl/cms/ folder) was all that was required. The original code in upload.tmpl:

<div class="field">
<input type="radio" name="site_path" value="0" checked="checked" />
&lt;<MT_TRANS phrase="Local Archive Path">&gt;/
<input name="extra_path_archive" /><br />

<input type="radio" name="site_path" value="1" />
&lt;<MT_TRANS phrase="Local Site Path">&gt;/
<input name="extra_path_site" />
</div>

And the revised code, creating the default “upload/” folder (look at value="upload/"):

<div class="field">
<input type="radio" name="site_path" value="0" checked="checked" />
&lt;<MT_TRANS phrase="Local Archive Path">&gt;/
<input name="extra_path_archive" value="upload/" /><br />

<input type="radio" name="site_path" value="1" />
&lt;<MT_TRANS phrase="Local Site Path">&gt;/
<input name="extra_path_site" value="upload/" />
</div>

The benefit of using the value="upload" approach—which only appears in the form input field, versus hard-coding it in—is that I can change the upload path if I want. I happily used this “upload” folder for quite some time, but as I mentioned, eventually I had a folder so full of files that I couldn’t find anything. Which leads to…

Making A Dynamic Upload Directory

I suppose it would be ideal to have uploads go into the same folder as the entry they relate to, but this isn’t always going to be easy. For example, if you use a file upload to create a new entry. You can manually type in the path, but sooner or later you’ll misspell or mistype and create some confusion. Plus, you need to keep typing those paths in. I don’t want to bother with any of that. I want an automated system to help track and organize my uploads.

http://www.eatdrinksleepmovabletype.com/upload/2005/10/upload-dynamic-thumb.gif

The easy way to automate such a thing is to upload files into a directory structure based on the current date, so that’s what I did. The below hacks will create a value of upload/<year>/<month>/; of course <year> is replaced by the current year and <month> is replaced by the current month. It’s also worth noting that this is a slightly more involved hack. Similar to the Default Upload Directory hack, this approach puts the upload directory into the form field, making it easy to change if you want.

The Easy Way

As a few others suggested, using JavaScript would be easier to institute than hacking Perl (as in The Hard Way, below).

Open tmpl/cms/upload.tmpl for editing. At the end of the document, add this:

<script type="text/javascript" language="JavaScript">
var date = new Date();
var m = date.getMonth() + 1;
var month = (m < 10) ? '0' + m : m;
var year = date.getFullYear();
document.forms[0].extra_path_archive.value = '/upload/' + year + '/' + month;
document.forms[0].extra_path_site.value = '/upload/' + year + '/' + month;
</script>

Save, and you’re done!

The Hard Way

Now superceded by The Easy Way, above.

Edit tmpl/cms/upload.tmpl from this:

<div class="field">
<input type="radio" name="site_path" value="0" checked="checked" />
&lt;<MT_TRANS phrase="Local Archive Path">&gt;/
<input name="extra_path_archive" /><br />

<input type="radio" name="site_path" value="1" />
&lt;<MT_TRANS phrase="Local Site Path">&gt;/
<input name="extra_path_site" />
</div>

Change it to this (specifically, the value="<TMPL_VAR NAME=DYNAMICDIR>" modification):

<div class="field">
<input type="radio" name="site_path" value="0" checked="checked" />
&lt;<MT_TRANS phrase="Local Archive Path">&gt;/
<input name="extra_path_archive" value="<TMPL_VAR NAME=DYNAMICDIR>" /><br />

<input type="radio" name="site_path" value="1" />
&lt;<MT_TRANS phrase="Local Site Path">&gt;/
<input name="extra_path_site" value="<TMPL_VAR NAME=DYNAMICDIR>" />
</div>

Next, edit lib/MT/App/CMS.pm. Look for the sub start_upload section at line 3736. The original code:

sub start_upload {
    my $app = shift;
    my $perms = $app->{perms}
        or return $app->error($app->translate("No permissions"));
    return $app->error($app->translate("Permission denied."))
        unless $perms->can_upload;
    my $blog_id = $app->{query}->param('blog_id');
    require MT::Blog;
    my $blog = MT::Blog->load($blog_id);
    $app->add_breadcrumb($blog->name, $app->uri . '?__mode=menu&blog_id=' . $blog->id);
    $app->add_breadcrumb('Upload File');
    $app->build_page('upload.tmpl', {
        local_archive_path => $blog->archive_path,
        local_site_path => $blog->site_path,
    });
}

Replace it with the following code. Specifically, note the new code right after sub start_upload { and the new line dynamicdir => $outdirectory,. Both are not indented so they’re easier to see.

sub start_upload {

my($sec); my($min); my($hour); my($mday); my($mon); my($year); my($wday); my($yday); my($isdst); my($outdirectory);

($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
$year+=1900; $mon+=1; # adjust the year and month
$outdirectory="/upload/$year/$mon/";

    my $app = shift;
    my $perms = $app->{perms}
        or return $app->error($app->translate("No permissions"));
    return $app->error($app->translate("Permission denied."))
        unless $perms->can_upload;
    my $blog_id = $app->{query}->param('blog_id');
    require MT::Blog;
    my $blog = MT::Blog->load($blog_id);
    $app->add_breadcrumb($blog->name, $app->uri . '?__mode=menu&blog_id=' . $blog->id);
    $app->add_breadcrumb('Upload File');
    $app->build_page('upload.tmpl', {
dynamicdir => $outdirectory,
        local_archive_path => $blog->archive_path,
        local_site_path => $blog->site_path,
    });
}

If everything worked ok, when you click the Upload File button in Movable Type you should see the default dynamic upload folder, as in the screenshot above! I should note that I have very little knowledge of Perl and had some help with this code.

If you want a upload/<year>/<month>/<day>/ structure, you can simply change $outdirectory="/upload/$year/$mon/"; to $outdirectory="/upload/$year/$mon/$mday/";.