Flexible downloads using pages in ProcessWire

2013/12/15 12:06 PM • ProcessWire Tutorial Comments (2)

You will be able to create a new page using template "PDF" (or any you setup), upload a pdf file. You then can select this page using page fields, or links in Wysiwyg. The url will be to the page and NOT the file itself.

This will allow to keep a readable permanent unique url (as you define it), unlike /site/assets/files/1239/download-1.pdf, and you'll be able to update/replace the uploaded file without worring about its filename. Further more the file will also have an id, the one of the page where it lives.

Clicking those links will download or open the file (when target="_blank") like it would be a real file on server with a path like /downloads/project/yourfile.pdf. You'll be also able to use the "view" action directly in the page list tree to view the file.

Further more you'll be able to esaily track downloads simply by adding a counter integer field to the template and increase it every time the page is viewed. Since the file is basicly a page.

This all works very well and requires only minimal setup, no modules and best of it it works in the same way for multi-language fields: Just create the language alternative fields like "pdf, pdf_de, pdf_es" and it will work without modifying any code!

Still with me? Ok. 

PW setup

Download folder: Create a template "folder" or "download-folder" with only a title needed. Create pages in the root like /downloads/project/ using this template.

Setup the template for the pdf files

  1. Create a new template in PW. Name it pdf
  2. Goto template -> URLs tab and set the URL end with slash to no. (So we can have /path/myfile.pdf as the URL)
  3. Create a new custom file field, name it pdf. Set its maximal count to 1 under -> Details tab.
  4. Add the pdf field created to the pdf template. Easy.
  5. Create a new "pdf" page using the pdf template under a download folder you created earlier.
  6. Give it the title and in the name field add ".pdf" to the end (could also leave as is)

Template PHP file for the pdf files

  1. Create the template file pdf.php in your /site/templates folder
  2. Add the following code:
/**
 * pdf.php
 */
if($page->pdf){
    wireSendFile($page->pdf->filename);
}

Done. 

To see the options you have with PW's wireSendFile() you can also overwrite defaults

if($page->pdf){
    $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' => false, 
    // string: filename you want the download to show on the user's computer, or blank to use existing.
    'downloadFilename' => '',
    );

    wireSendFile($page->pdf->filename, $options);
}

Simple and powerful isn't it? Try it out.

Some thoughts advanced

Create as many file types as you like. It might also be possible to use one "filedownload" template that isn't restricted to one field type but evaluate it when being output using $page->file->ext, or save the file extension to the page name after uploading using a hook.

One last thing. You can add other meta fields or preview images to the template and use those to create lists or detail pages. It's all open to goodness. Again all without "coding" and third-party modules.

Further more you can use the excellent TemplateDecorator to add icons per template and have a nice pdf icon for those pages.

This as a base one could also easily create a simple admin page for mass uploading files in a simple manner, and create the pages for the files automaticly. ImagesManager work in the same way.

Cheers

2013/12/15 12:06 PM | ProcessWire | Tutorial

Comments

  • Torsten 2014-02-06 20:58:48

    Great article!

    » Further more you'll be able to esaily track downloads simply by adding
    » a counter integer field to the template and increase it every time the
    » page is viewed. Since the file is basicly a page.

    do you have an example for this?

    thanks!

  • soma 2014-02-06 22:46:14

    Thanks!

    Add a new field named "counter" type integer to your template. In there, before the code to wireSendFile(), you'd update that field and save it to the page back right in the template.

    $page->of(false);
    $page->counter += 1;
    $page->save();
    $page->of(true);
    wireSendFile($page->pdf->filename, $options);

    The of(false) - is turning off output formatting in case needed for the save().

    If you don't want to update modified and modified user of the page on each save you simply call it with option like this:

    $page->save(array("quiet" => true));

    So every time the file gets downloaded the counter will increase by one.

    Virtually anything can be done inside the template before wireSend(). Saving something using $db->query() or $database->query() in a custom DB table would be a possible alternative.