What's in this article

      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:

      files-in-folder-list.png

      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":

      block-designer-name.png

      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:

      text-box-field.png

      Then set the field name and handle:

       

      folder-name-and-handle.png

      Install the block

      We then just need to go to block types:

      block-types.png

      And install the block:

      install-block.png

      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:

      block-files.jpg

      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:

      block-file-list.png

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

      editing-file-list-block.png

      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:

      Related Articles

      Keep up to date

      Subscribe to receive occasional email newsletters from us.