Page 1 of 1

Uploads - Display by Category Listing [SOLVED]

Posted: Wed Jul 17, 2013 4:08 pm
by tophers
I've combed through a lot of posts on this topic (some going back to 2009!), and still can't find a solution, though some have come tantalizingly close. I want to display my Uploaded files by category - I'm actually adding an accordion functionality to expand/collapse the list, but that isn't the issue. The problem is that I can't get the files sorted first by category. They seem to default to either:
A) the order they were added to the system, or;
B) by name of the file, if I sort by sortorder='name_asc' or 'name_desc'

The problem is I get duplicated Category headings instead of all files under one category being grouped - I have multiple headings for some categories:
Image

I tried the Category Listing option to see if I could decipher how it worked, but it's failing:
Image

So I'm stumped. I've tried a few solutions I discovered out there, including one that Goran posted on his blog http://www.i-do-this.com/blog/69/Sortin ... in-foreach, but nothing seems to work. Since the Category Listing option is failing, is this a bug?

Running CMSMS 1.11.7, CGExtensions 1.36.2, Uploads 1.16.4

Re: Uploads Category Listing

Posted: Wed Jul 17, 2013 5:01 pm
by calguy1000
Actually... goran's instructions are correct. You need a function to sort the summary view by the category member variable... then the accordion will work.

I call {Uploads category=all}
and the template that does the accordion is fairly simple.

Code: Select all

{sort_udt data=$items} {* from gorans example *}
{cge_array::objsort($items,'category')} {* new method in CGExtensions 1.37 *}
{$category=''}
<div id="test_accordion">
{foreach $items as $rec}
  {if $rec->category != $category}
    {if $category != ''}</div><!-- close wrapper -->{/if}
    {$category=$rec->category}
    <h3>{$category}</h3>
    <div><!-- open wrapper -->
  {/if}
  <div>
  <a href="{$rec->detailurl}">{$rec->upload_name}</a>
  </div>
{/foreach}
  </div><!-- close wrapper -->
</div>

<__script__ type="text/javascript">
$('#test_accordion').accordion();
</__script>

Re: Uploads Category Listing

Posted: Wed Jul 17, 2013 5:08 pm
by calguy1000
Followup: I wrote the cge_array::objsort method as a generic method to sort an array of objects by one member for CGExtensions 1.37 (not yet released).

But a simple UDT like in goran's example would work too.

Re: Uploads Category Listing

Posted: Thu Jul 18, 2013 3:29 pm
by tophers
Success! Thank you Calguy - I now have it sorting by Category (either alphabetically or by the order they were entered into the system). For those just tuning in, here's what I did:

Call the module on your page - {cms_module module='Uploads' category='all'}

Create a UDT (called 'sort'):

Code: Select all

if (!function_exists('do_sort')) {
    function do_sort($a, $b) {
        return $a->upload_category_id > $b->upload_category_id;
    }}

$data = $params['data'];
usort($data, 'do_sort');
$smarty->assign('sorted', $data);
If you'd like to sort your categories alphabetically, simply change 'upload_category_id' to 'category' in the UDT above.

In the Uploads module, change the following in your Summary Template:

from
{foreach from=$items item='entry' name='uploads'}

to
{sort data=$items}<!--calls the newly created UDT-->
{foreach from=$sorted item='entry' name='uploads'}<!--swaps $items to $sorted-->

I haven't tested Calguy's accordion template, but here's a simple one that will group items under their category heading, and should be a good launching point for your own:

Code: Select all

<div id="categories">

    {assign var='current_category' value=''}
    
    {sort data=$items}
    {foreach from=$sorted item='entry' name='uploads'}
    
        {if isset($entry->download_url)}
            <!-- check for new Category start -->
            {if $current_category != $entry->category}
            
                <h3>{$entry->category}</h3>
                <!-- assign this items category to current -->
                {assign var='current_category' value=$entry->category}
    
            {/if}
    
            <!-- item -->
            <!-- generate a file download link, size and any additional fields -->
            <p><strong><a class="downloadurl" href="{$entry->download_url}" title="{$entry->upload_name}" target="_blank">{$entry->upload_name}</a></strong>&nbsp;<span class="size">({$entry->size}&nbsp;kb)</span></p>
            {if isset($entry->fields)}
              {foreach name=fields from=$entry->fields key='fldname' item='field'}
                {$field.name}: {$field.value}<br/>
              {/foreach}
            {/if}
            <!-- item -->
        {/if}
    {/foreach}

</div>
And in case you haven't been paying attention (or read as many posts on the topic as I have!), to further protect any files in your chosen directory, make sure to drop a .htaccess file into the directory containing your files that contains:

Code: Select all

<limit GET POST HEAD DELETE>
order deny,allow
deny from all
allow from 127.0.0.1
</limit>
NOTE: this method only seems to work with modules that use a script to access the files (such as Uploads or Download Manager). If the module produces a direct path to the file that matches it's actual location, this .htaccess file will block ALL access, so don't use it!

Once again, thanks to Calguy, and of course uniqu3 (Goran) for his solution (which can be read at http://www.i-do-this.com/blog/69/Sortin ... in-foreach).