Download Area with HappyFiles

Aside from the series I’m currently writing on how to create custom galleries and sliders with HappyFiles, Metabox and Bricks, I have developed a snippet to output all subfolders of a specific folder. This one is very useful if you want to create a custom “Download Area” for example. You can manage all your downloadable files from your WP Media section and don’t have to manually update that page every time a document/image changes, gets removed or a new one gets added!

What’s included in the snippet?

The snippet takes care of the following things:

  • Icon generation
  • The possibility to output it with or without CSS rules applied!
  • Automatically group the files/images by their folder
  • Filter to add custom Links

What you should do

Basically, all you have to do is create the folder structure and upload your files. You need to take care that all folders you want to include are the child of one parent folder. And the files inside the parent folder don’t get included in my script. So it is only targeting the child folders! A possible setup could look like this:

Although I have some files here in my parent folder they don’t get included in the output (as seen in the image on top of that post). That’s one thing you should keep in mind!

Full Source Code

Here you can find the full source code of the snippet. I’m gonna explain the steps to take later on:

<?php
function get_happyfile_childFolders($parentSlug)
{
    $happyfile_terms = get_terms([
        "taxonomy" => HAPPYFILES_TAXONOMY,
        "hide_empty" => false,
    ]);
    
    $parentID = false;
    // GET THE ID OF THE PARENT FOLDER
    foreach ($happyfile_terms as $term) {
        if ($term->slug == $parentSlug || $term->name == $parentSlug || $term->term_id == $parentSlug) {
            $parentID = $term->term_id;
        }
    }
    
    if (!$parentID){
        return false;
    }

    $folders = [];
    foreach ($happyfile_terms as $term) {
        if ($term->parent == $parentID) {
            $term = json_decode(json_encode($term), true);
            $folders[$term["slug"]] = $term;
        }
    }
    return $folders;
}

function outputFiles($folderSlug)
{
    global $wpdb;
    $folders = get_happyfile_childFolders($folderSlug);
    
    if (!$folders){
        echo 'No Folder found, please check the passed Parameter!';
        return;
    }
    echo '<div class="downloads">';
    


    foreach ($folders as $folder) {
        $files = $wpdb->get_results(
            "SELECT * FROM {$wpdb->prefix}term_relationships WHERE term_taxonomy_id = {$folder["term_id"]}",
            OBJECT
        );
       
       // ADD CUSTOM CONTENT TO THE SPECIFIED FOLDER (via Filter)
       $customContent = [];
       $customContent = apply_filters('foldersCustomContent', $customContent, $folder['name']);
       

        echo '<div class="folder">';
        echo '<div class="folder-heading">';
        echo "<h2>{$folder["name"]}</h2>";
        echo "</div>";

        echo '<div class="folder-content">';
        foreach ($files as $file) {
            $url = wp_get_attachment_url($file->object_id);
            $title = get_the_title($file->object_id);

            echo '<div class="file">';
            echo '<i class="ti-file"></i>';

            echo "<a href='{$url}' target='_blank'>{$title}</a>";

            echo "</div>";
        }
        
        // OUTPUT CUSTOM CONTENT AFTER HAPPY-FILES FILES:
       if ( count($customContent) != 0 ) {
        foreach ($customContent as $title=>$file) {

            echo '<div class="file">';
            echo '<i class="ti-file"></i>';

            echo "<a href='{$file}' target='_blank'>{$title}</a>";

            echo "</div>";
        }           
       }        
        
        

        echo "</div></div>";
    }
    echo "</div>";
}

function outputDefaultStyles()
{
    ?>
<style>
@media only screen and (min-width: 0px) {
    :root{
      --folders-primary: #004f9e;
      --folders-textOnPrimary: white;
      --folders-linkColor: #004f9e;
      --folders-iconColor: #e1e1e1;
    }
    .downloads{
        width: 100%;
        display: flex;
        gap: 40px;
        flex-wrap: wrap;
    }
    
    /* FOLDER-WRAPPER */
    .folder{
        max-width: 100%;
        width: 100%;
        box-shadow: 0 0 20px 0 rgba(0,0,0,0.1);
        background-color: white;
    }
    .folder-heading{
        min-height: 48px;
        display: flex;
        flex-direction: column;
        justify-content: center;
        background-color: var(--folders-primary);
        padding: 0 12px;
    }
    .folder-content{
        padding: 24px;
        padding-top: 8px;
    }
    
    .folder-heading h2{
        font-size: 22px;
        color: var(--folders-textOnPrimary);
    }
    
    /* DATEIEN */
    .file{
        margin-bottom: 8px;
    }
    .file > i{
        margin-right: 5px;
        font-size: 26px;
    }
    
    .file > a{
        font-size: 18px;
        margin-left: 30px;
        position: relative;
        color: var(--folders-linkColor);
    }
    .file a:before{
        content: "";
        width: 25px;
        height: 25px;
        position: absolute;
        top: 0px;
        left: -35px;
        background-color: var(--folders-iconColor);
        -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3C!-- Font Awesome Pro 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --%3E%3Cpath d='M216 0h80c13.3 0 24 10.7 24 24v168h87.7c17.8 0 26.7 21.5 14.1 34.1L269.7 378.3c-7.5 7.5-19.8 7.5-27.3 0L90.1 226.1c-12.6-12.6-3.7-34.1 14.1-34.1H192V24c0-13.3 10.7-24 24-24zm296 376v112c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V376c0-13.3 10.7-24 24-24h146.7l49 49c20.1 20.1 52.5 20.1 72.6 0l49-49H488c13.3 0 24 10.7 24 24zm-124 88c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20zm64 0c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20z'/%3E%3C/svg%3E");
        mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3C!-- Font Awesome Pro 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --%3E%3Cpath d='M216 0h80c13.3 0 24 10.7 24 24v168h87.7c17.8 0 26.7 21.5 14.1 34.1L269.7 378.3c-7.5 7.5-19.8 7.5-27.3 0L90.1 226.1c-12.6-12.6-3.7-34.1 14.1-34.1H192V24c0-13.3 10.7-24 24-24zm296 376v112c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V376c0-13.3 10.7-24 24-24h146.7l49 49c20.1 20.1 52.5 20.1 72.6 0l49-49H488c13.3 0 24 10.7 24 24zm-124 88c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20zm64 0c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20z'/%3E%3C/svg%3E");       
    }
}


@media only screen and (min-width: 800px) {
    .folder{
        width: calc(50% - 20px);
    }
}
</style>

<?php
}

?>

How to use that snippet?

Copy that code above to your child theme’s functions.php or code execution tool of your choice.

Create a page in WordPress and open it with Bricks. Inside Bricks, you would need to use the Code element: There are two possibilities to output the files, with or without CSS styles:

With CSS styles you need to call it the following way:

outputDefaultStyles();
outputFiles( 'SLUG/NAME/ID' ); // pass the slug, name or ID of your happyfiles-parentfolder here

Updated

You can now use either the SLUG, NAME, or the ID of your HappyFiles Folder as Argument for the function “outputFiles()” as described above!

Without CSS styles you just leave out the first function outputDefaultstyles(). Then you can write your own CSS Styles to it. But I’ve provided a pre-styled possibility where you can also change the color output inside the CSS variables at the beginning of the function outputDefaultStyles();

How to adapt the Icon?

You can manually change the Icon in front of each file, all you need to do is download an Icon from FontAwesome, Bootstrap Icons or anything else and URL encode the SVG content of that file. You could use a tool like this one here: https://yoksel.github.io/url-encoder/

Once you have that URL encoded SVG you need to change that code in the provided source code. I think it’s pretty easy to localize where to change that, but just in case: inside the outputDefaultStyles() function you need to localize the line where it says .file a:before {. Then find the line with -webkit-mask-image: url( and replace the content with your icon!

Filter to add custom Content

The filter adds the possibility to add custom links inside any subfolder!

Want to have an entire Section with custom Links?

Since that filter is running inside the loop through all subfolders you would need to create an empty subfolder to create a Section with only custom links. Of course, you could also add something inside that folder, then your custom links get mixed with your folder contents!

You can call the filter inside of your code block by doing so:

add_filter( 'foldersCustomContent', function( $links, $name ) {

	// Here you can specify the foldername to which you want to add custom links.
	if ( $name != 'THE_NAME_OF_THE_FOLDER_YOU_WANT_TO_ADD_SOMETHING' ) {
		return $links;
	}
	
	$links['NAME OF THE LINK'] = 'https://example.com';
	$links['NAME OF ANOTHER LINK'] = 'https://example.com';

	return $links;
}, 10, 2);

You have access to two variables inside that function

  1. $links which is an array holding all the links of the current looped folder. Here you can add any links or even external files by doing it like I did in the example.
  2. $name which is the NAME (not the slug) of the folder you want to target. So it’s the pretty name you defined inside of HappyFiles!

That’s it. Now you’ve added custom links to your folder loop!

Downside:

The query itself could be optimized, although I didn’t recognize any performance issues you could achieve the same with wp_query instead of $wpdb!

Summary

This is definitely not a beginners article, but it should also work for beginners if you copy & paste the snippets and play around with the CSS only. I know it’s not as visual as using a page-builder, but it does its job pretty well and it saves a lot of time in managing download areas on any website. It’s super cool to use because you have to upload your files any way and with that snippets, you don’t need to think about all the different locations you need to add your uploads because that’s handled by the script! Hope you like it! 😉

Instant access to 390+ Bricks code tutorials with BricksLabs Pro

3 comments

  • Michael Kokott

    I have set this up with wpcodebox2, but all i get on the frontpage is:

    outputDefaultStyles(); outputFiles( 'PDFs' ); // pass the slug, name or ID of your happyfiles-parentfolder here

    The code should be executed as a simple output is executed.

    Any Idea?

    Thanks

  • Amanda Lucas

    Is there a way to change the order of how things are ordered. I have the order changed in the media folder but its not outputting that way in the front end.

    • Marcel

      Was wondering the same. If there was a ordering mechanism, this would be very helpfull. But this tutorial itself is already awesome! Trying it out on a brand new project im just starting to work on =)

Leave a Reply to Amanda Lucas (Cancel Reply)