Simple file downloads with ProcessWire

01.09.2017 by Jens Martsch

This tutorial shows you how to add a download area on your website with the ProcessWire CMS/CMF (Version 3).

Say you want to have a download area on your website or an option to download files on a blog entry page?

I've got you covered and will guide you trough the steps to accomplish this task.

1.) First go to "Setup > Fields" and create a new field "files".

2. Now create a new template "downloads" or use a already existing template and add the "files" field to it.

3. Then go to the templates "URLs" tab and click "Allow URL segments".

We will be using the URL segments to give decide which file to download.

4. Now create a new page that uses this template, for example name it "Downloads" and as the name (also URL) enter "downloads".

5. Upload some files to the file field and save and publish the page.

6. Now add the following code to your site/templates/_init.php:

<?php
if ($input->urlSegment1 == 'download') {
    $download_options = array(
        // boolean: halt program execution after file send
        'exit' => true,
        // boolean|null: whether file should force download (null=let content-type header decide)
        'forceDownload' => true,
        // string: filename you want the download to show on the user's computer, or blank to use existing.
        'downloadFilename' => '');
    session_write_close();
    if ($input->urlSegment2 && $input->urlSegment3) {
        $pagefile = $pages->get($input->urlSegment2)->files[$input->urlSegment3];
        if ($pagefile) {wireSendFile($pagefile->filename, $download_options);
        }
    }
}

7. Create a new file site/templates/download.php (filename should match the name of the template you created in step 2) and add the following code to it:

<?php
foreach ($page->files as $file) {
    echo "<a href='download/{$page->id}/{$file->name}'>download {$file->name}</a><br>";
}

As you can see in the link the first URL segment is named "download" which is catched by _init.php. URL segments two and three identify where the file is located.

When someone now clicks the download link, the _init.php searches the filename (URL segment 3) on the page with the id of URL segment 2.

That´s it.

PRO-TIP: The downside when implementing this in the _init.php is, that you can't send a Wire404Exception, because _init.php gets included (prepended) and PHP doesn´t like exceptions in included files. If you paste this code into one of your templates you could add throwing a Wire404Exception.