Make a block in Concrete CMS with download links for all the files in a specific folder

The problem

I was working on a client project and needed to list a large amount of PDF files, so the user could download them. It didn’t make sense to use the standard File block, where I would need to add them one by one and it could be potentially fiddly to update in the future.

So rather than adding them manually, one by one using File blocks, I created a custom block, that would list them all out in the order of my choosing.

Here is the result:

Read on to find out how to do this.

Create the block in Block Designer

First of all, I used Block Designer to create the basic block. It’s a really handy tool that quickly creates the block, including controller, view and form with fields that the user add details to when adding the block to the page.

We called the block “MSM All Files in Folder”:

And the only field we added was a textbox with the name of the Folder that we want to list all the files from.

To do this choose a Text Box field:

Then set the field name and handle:

Install the block

We then just need to go to block types:

And install the block:

Edit the view file

Now our block is ready, we can edit it with the code to show files from a folder.

Here is an overall look at our blocks code files:

Here is the default code in our view file:

<?php defined("C5_EXECUTE") or die("Access Denied."); use Concrete\Core\Tree\Node\Type\FileFolder; use Concrete\Core\File\FolderItemList; ?> <?php if (isset($folder) && trim($folder) != "") { ?> <?php if(h($folder)) { } echo h($folder); ?> <?php } ?>

Essentially it just writes out to the page, the name of our folder.

Amend view to be like this:

Now we add our code to get the folder that matches the name we enter in our block and list all files in it:

<?php defined("C5_EXECUTE") or die("Access Denied."); use Concrete\Core\Tree\Node\Type\FileFolder; use Concrete\Core\File\FolderItemList; ?> <?php $folder = FileFolder::getNodeByName($folder); if (is_object($folder)) { echo '<div class="msm-file-list">'; echo '<div class="box half ps-0">'; $files = []; // if we have a folder we need to grab everything inside and then // recursively go through the folder's content // if what we get is a file we list it // otherwise if it's another folder we go through it as well $walk = function ($folder) use (&$files, &$walk) { $list = new FolderItemList(); $list->filterByParentFolder($folder); $list->sortByNodeName(); $nodes = $list->getResults(); foreach ($nodes as $node) { if ($node->getTreeNodeTypeHandle() === 'file'){ $files[] = $node->getTreeNodeFileObject(); } elseif ($node->getTreeNodeTypeHandle() === 'file_folder'){ $walk($node); } } }; $walk($folder); // We are done going through all the folders, we now have our file nodes foreach ($files as $file) { //echo sprintf('%sfile name is %s and URL is %s%s', '<p>', $file->getTitle(), $file->getURL(), '</p>'); $fileName = str_replace(".pdf", "", $file->getTitle()); // Remove .PDF Extension echo '<a href="'.$file->getURL().'" target="_blank">' . $fileName .'</a>'; } echo '</div>'; echo '</div>'; } ?>

Thanks to Nour Akalay: https://stackoverflow.com/questions/46924783/concrete5-cms-get-all-file-inside-a-file-manager-folder-programmatically

Here is the code, step by step

Let’s break down the code above, step by step…

Declare our $folder object

Add the following line:

$folder = FileFolder::getNodeByName($folder);

We then need to make sure it is actually a Folder:

if (is_object($folder)) { ... }

We add some markup and a new empty array to contain our list of files:

echo '<div class="msm-file-list">'; echo '<div class="box half ps-0">'; $files = [];

Grab everything in our folder

We go through the folder’s content, if we find a file we list it and if necessary, go through sub folders:

$walk = function ($folder) use (&$files, &$walk) { $list = new FolderItemList(); $list->filterByParentFolder($folder); $list->sortByNodeName(); $nodes = $list->getResults(); foreach ($nodes as $node) { if ($node->getTreeNodeTypeHandle() === 'file'){ $files[] = $node->getTreeNodeFileObject(); } elseif ($node->getTreeNodeTypeHandle() === 'file_folder'){ $walk($node); } } }; $walk($folder);

Write out our file links

Now we’re ready to loop through the set of files and write out our HTML anchor tag for each file. Also closing our is_object($folder) function:

foreach ($files as $file) { $fileName = str_replace(".pdf", "", $file->getTitle()); // Remove .PDF Extension echo '<a href="'.$file->getURL().'" target="_blank">' . $fileName .'</a>'; } echo '</div>'; echo '</div>'; }

In this case I also wanted to remove the PDF extension from the file name.

The result

Here is the resulting block:

When editing the block, all you have to do is add the name of the folder:

What’s next?

Hope this was useful for your project, if you need any help doing this, please get in touch.

Article by David Reeder. LinkedIn Profile: https://www.linkedin.com/in/david-e-reeder/

Originally published at https://www.madesimplemedia.co.uk on August 12, 2025.

Learn more Make a block in Concrete CMS with download links for all the files in a specific folder

Leave a Reply