What's in this article
What's in this article
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.
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:

We then just need to go to block types:

And install the block:

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.
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
Let's break down the code above, step by step...
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 = [];
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);
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.
Here is the resulting block:

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

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/
Related Articles
09 July 2025
Concrete CMS comes with very flexible, granular user permissions. When setting permissions to advanced, we can give users access to edit as much or… Read more
16 October 2024
Caching is essential for making web pages load fast, but you also need an acceptable level of control to avoid other issues. Concrete CMS features a… Read more
13 May 2024
As a website owner you will want to add 301 redirects when you have a page or product that has been discontinued. If you don't do this, your users… Read more
Keep up to date
Subscribe to receive occasional email newsletters from us.