If you’ve ever embedded a PDF file or other downloadable file in WordPress posts or pages using the standard “Add Media” button, you probably know what a pain it can be if and when — but most likely when — that file needs to be updated.
You can’t just upload the newly updated file to the Media Library and expect “voila” to happen.
Even if the updated file has the same filename as the original, WordPress will rename it on upload rather than replace the old one with the new one. (I’ve tried a plugin that offers this replacement functionality, but it wasn’t user-friendly and fell short in other ways.)
What you’ll have to do to replace the file is:
- remember all the places you embedded it
- remove the old embed in all those places
- add the new embed in all those places
Not the end of the earth, but not the best use of anyone’s time, either. Especially if there are lots of documents that get updated or some documents that get updated a lot or some combination of the two.
So I created my own plugin — “Downloads” — for replacing downloadable files.
(Note: This is a plugin with a small “p”. More work is needed before it can be submitted for inclusion in the WordPress repository.)
A Web site for a private school was the inspiration.
The project that inspired this solution was a Web-site redesign for a private school. This school — like many, I suppose — offers a whole lot of documents, most of them in PDF format, for students and parents, both actual and prospective.
Lots of downloadable documents.
There are:
- school-year calendars for each of three academic programs
- application forms
- forms for requesting transcripts
- field trip permission forms
- handbooks
- course descriptions
- event flyers
- and more.
In the rest of this article I’ll describe the basic features, elements and operation of the plugin, without getting too much into the weeds. If you’re interested in learning more, let me know in the comments.
Features of the Plugin
Feature #1. Insert Documents by Shortcode
One of the main components of the plugin is a custom shortcode used to embed each Download (more on the shortcode below).
Feature #2. Conditional Display
Each downloadable document can have either a “Start Showing On…” date and/or a “Stop Showing After…” date. Wherever a Download is embedded in a page or post (or widget, for that matter), the plugin “knows” whether to display the link based on those dates and the current date.
This means two things:
- You can embed a Download on a page or post even before you want it to appear on the front end of the site. This is almost exactly like post-dating a blog post to schedule it to appear in the future.
- Conversely, the plugin will automatically hide any Download that should not appear after a specific date. (For example, you might want to remove a field trip application form after the field trip occurs.) You needn’t edit the page(s) or post(s) to manually remove the embed, as long as you specified the proper date parameters.
Feature #3. Automatic Inclusion on Front End
I made a custom template for this page. The template’s code automatically displays the link for every downloadable document whose type (custom taxonomy) is “Calendar” as long as the current date is on or after the designated “Start Showing On…” date and on or before the “Stop Showing After…” date.
Feature #4. Automatic Replacement
This is the feature that drove me to create the plugin in the first place.
Invariably, Downloads need to be replaced from time to time, due either to errors or actual changes.
Because each downloadable document is identified by its post ID — rather than by its filename — you can just replace the obsolete document with the new one in the Downloads administrative panel, and voila!
First click the “Remove” icon…
Then add the new file.
There are five main elements of this plugin:
- a custom post type for downloadable documents (“Downloads”)
- custom fields (using the Advanced Custom Fields plugin for specifying metadata for each document)
- a custom taxonomy
- a shortcode for displaying the download links where needed
- a custom page template for displaying calendars
Element #1. The Custom Post Type
The Custom Post Type itself is very simple. This new post type (named “Download”) supports only the ‘title’ and “page-attributes” features of WordPress’ post edit screen. The ‘title’ is the internal (for office use only) name for the download. Enabling page attributes permits assigning order values, for the purpose of sorting, where desired.
Element #2. Custom Fields
This is where the meaty stuff of the plugin happens.
Here’s a screen shot of the ACF Field Group for downloads:
The fields:
- Title (required, internal use only)
- Academic Program (optional; e.g., “K-12”, “Independent Study”, etc.)
- Front-End Document Title (required)
- Document Description (optional and hidden on front end by default)
- Document File (required)
- Start Showing On… date (optional, supports date-picker)
- Stop Showing After… date (optional, supports date-picker)
Element #3. Custom Taxonomy
I registered a custom taxonomy called “download_cat” and associated it with the Downloads custom post type. As of this writing, the only
download_cat
value that has any special power is “Calendar”. As I mentioned above, the template’s code automatically displays the HTML for every downloadable document whose type (download_cat) is “Calendar” as long as the current date is on or after the designated “Start Showing On…” date and on or before the “Stop Showing After…” date.
Element #4. The Downloads Shortcode
Format for Shortcode:
The format for the shortcode that embeds a Download into a page or post is as follows. The only required attribute is the id
. Where I show optional values for attributes (e.g., “true|false”), the first element is the default.
[ea_download id="nnn" block="true|false" show_description="false|true" href_only="false|true"]
Shortcode Function:
Here’s the actual code for generating the HTML from the shortcode. If you’re interested in a description of how it works, let me know.
function nwb_shortcode_download($atts) { global $post; $atts = shortcode_atts( array( 'id' => '', 'block' => 'true', 'show_description' => 'false', 'href_only' => 'false', ), $atts, 'ea_download' ); if ( empty($atts['id']) ) { return; } $doc_id = $atts['id']; $data = get_post_custom($doc_id); $program = $data['program'][0]; $title = $data['document_title'][0]; $description = $data['document_description'][0]; $show_from = $data['show_from'][0]; $show_through = $data['show_through'][0]; $file = $data['document_file'][0]; // Test from and to dates $today = date('Y-m-d'); if ( !empty($show_from) && $today < $show_from ) { return; } if ( !empty($show_through) && $today > $show_through ) { return; } $file_url = wp_get_attachment_url($file); $href_start = '<a target="_blank" href="' . $file_url . '">'; $href_end = '</a>'; /* To return only the link */ if ( 'true' == $atts['href_only']) { $output = $file_url; return $output; } if ( 'true' == $atts['block']) { $output = '<div class="download">'; $output .= '<div class="name">' . $href_start . $title . $href_end . '</div>'; if ( $atts['show_description'] == 'true' && !empty($description)) { $output .= '<div class="description">' . $description . '</div>'; } $output .= '</div>'; } else { $output = '<span class="name">' . $href_start . $title . $href_end . '</span>'; } return $output; } add_shortcode('ea_download', 'nwb_shortcode_download');
Element #5. The Custom Page Template for Academic Calendars
Here are pertient blocks of code from the custom page template for grabbing and diplaying academic calendars. Again, if anyone is interested in more information, please let me know.
Custom Query:
global $post; $args = array( 'post_type' => 'download', 'order' => 'ASC', 'orderby' => 'menu_order', 'tax_query' => array( array( 'taxonomy' => 'download_cat', 'field' => 'slug', 'terms' => 'calendar', ), ), 'posts_per_page' => -1, ); $cal_query = new WP_Query($args);
Rendering the HTML on the page:
<?php if ( $cal_query->have_posts() ) : while ( $cal_query->have_posts() ) : $cal_query->the_post(); ?> <?php $doc_id = $post->ID; $data = get_post_custom($doc_id); $program = $data['program'][0]; $title = $data['document_title'][0]; $description = $data['document_description'][0]; $show_from = $data['show_from'][0]; $show_through = $data['show_through'][0]; $file = $data['document_file'][0]; // Test from and to dates $today = date('Y-m-d'); if ( !empty($show_from) && $today < $show_from ) { continue; } if ( !empty($show_through) && $today > $show_through ) { continue; } $file_url = wp_get_attachment_url($file); $href_start = '<a target="_blank" href="' . $file_url . '">'; $href_end = '</a>'; /* Assemble the output */ $output = '<section>'; $output .= '<div class="download">'; $output .= '<div class="name">' . $href_start . $title . $href_end . '</div>'; if ( $atts['show_description'] == 'true' && !empty($description)) { $output .= '<div class="description">' . $description . '</div>'; } $output .= '</div>'; $output .= '</section>'; echo $output; ?> <?php endwhile; ?> <?php wp_reset_postdata(); ?> <?php endif; ?>
Tying it Up
Here are screen shots of the “Forms & Downloads” page followed by the code that makes it happen.
Screen shots


The code entered into the page:
<h2 id="orientation">Orientation, Handbooks & General Forms</h2> [ea_download id="4709"] [ea_download id="5099"] [ea_download id="4785"] <h2 id="distance-learning">Distance Learning</h2> [ea_download id="4787"] [ea_download id="4788"] [ea_download id="4790"] <h2 id="summer-school">Summer School</h2> [ea_download id="4792" show_description='true'] [ea_download id="4791" show_description='true'] <h2 id="other-forms">Other Forms & Downloads</h2> [ea_download id="5473" show_description="true"] [ea_download id="4786"] [ea_download id="4771" show_description='true'] [ea_download id="5550" show_description='true'] [ea_download id="5553" show_description='true']
Comments Welcome
I guess I ended up covering a lot of ground after all. But if you have questions or are interested in knowing more, please let me know in the comments below.
Leave a Reply