Forum

Thread tagged as: Question, Problem, Configuration

Excluding unused categories in a category list?

Is there a way of excluding categories that have not been checked/ticked by the editor?

I'm creating a property site where there's 20+ towns/areas which won't all be used at any one time. (List and details pages with categories).

So ideally I need a list of all the area/town categories that have only been checked/ticked by the editor. (A short category list rather the whole list rather where 75% of the category links would return noresults.

I believe Perch blog has this behaviour.

David Owen

David Owen 0 points

  • 6 months ago
Hussein Al Hammad

Hussein Al Hammad 64 points
Registered Developer

Hello David,

So ideally I need a list of all the area/town categories that have only been checked/ticked by the editor.

You may be able to achieve this with perch_content_custom() (and perch_template()) instead of perch_categories().

// get categories that have been selected
$categories = perch_content_custom('Properties', [
    'template' => 'category_list.html',
    'skip-template' => true,
]);


// remove duplicates from $categories


// render template with perch_template()
perch_template('content/category_list.html', $categories);

I can't get your example to work. I can get a list of all the categories ticked (from the list of the list and details page)...

HTML

<ul class="prodcats">
    <li class="ProdCatTag"><a class="CatTag" href="/category.php?cat=area/yeadon/">Yeadon</a></li>
    <li class="ProdCatTag"><a class="CatTag" href="/category.php?cat=area/ilkley/">Ilkley</a></li>
    <li class="ProdCatTag"><a class="CatTag" href="/category.php?cat=area/harrogate/">Harrogate</a></li>
    <li class="ProdCatTag"><a class="CatTag" href="/category.php?cat=area/yeadon/">Yeadon</a></li>
 </ul>

PHP

<?php 
    // This creates a list all the products in one long list of categories ticked including duplicates
     perch_content_custom('Properties', array(
      'template' => 'category_tags_used.html',
    ));  
    ?>

Template

<perch:before>
    <h2 class="catTitle">Sort by Area</h2>
        <ul class="prodcats">
          </perch:before>
              <perch:categories id="area" label="Area Location" set="area" display-as="checkboxes" help="Select a category" divider-before="Categories">
                  <li class="ProdCatTag"><a class="CatTag" href="/category.php?cat=<perch:category id="catPath" />"><perch:category id="catTitle" /></a></li>
              </perch:categories>
          <perch:after>
        </ul>
 </perch:after>

However, I need this list to...

  1. Sort them in alphabetical order.
  2. Remove the duplicates

For example in a property list of four properties cats ticked with area1, area2, area,3 area1. I need to remove the duplicates.

Then I'm there. Any pointers where I'm going wrong?

Hussein Al Hammad

Hussein Al Hammad 64 points
Registered Developer

I think my example above is actually flawed.

I thought of a better approach. I think something like the following should work:

Your page.php:

// get your proerties
$properties = perch_content_custom('Properties', [
    'skip-template' => true,
]);

$catPaths= [];

// loop through your properties and get the categories from the field "area"
foreach($properties as $property)
{
    foreach($property['area'] as $catPath)
    {
        $catPaths[] = $catPath;
    }
}


// remove duplicates from the categories array
$catPaths = array_unique($catPaths);

// output your categories sorted alphabetically
perch_categories([
    'set' => 'area',
    'template' => 'your_template.html',
    'sort' => 'catTitle',
    'sort-order' => 'ASC',
    'filter' => 'catPath',
    'match' => 'in',
    'value' => implode(',', $catPaths),
]);


And your template templates/categories/your_template.html doesn't need to include perch:categories pair tag:

<perch:before>
<h2 class="catTitle">Sort by Area</h2>
<ul class="prodcats">
</perch:before>

<li class="ProdCatTag"><a class="CatTag" href="/category.php?cat=<perch:category id="catPath" />"><perch:category id="catTitle" /></a></li>

<perch:after>
</ul>
</perch:after>

Hopefully this works! If not, perhaps others can come up with a better approach.

Duncan Revell

Duncan Revell 74 points
Registered Developer

Another approach to take is the following:

perch_categories(['set'=>'area','sort'=>'catTitle','sort-order'=>'ASC','each'=>function($item) {
if (PerchUtil::count(perch_content_custom('Properties', ['skip-template'=>true, 'category'=>$item['catPath']])) > 0) return $item;
}]);

We're grabbing each category and filtering the 'Properties' region using that category - if the property count is 0, we don't pass that category to the output. This method does produce a database query for each category, so I would run it with debug switched on to see if makes an impact for your setup or not (it shouldn't really - it's basically the same query being repeated, so the query optimiser should handle it). You do have to make a slight change to the category template with this though - an example using the default category.html template:

<perch:before><ul></perch:before>
<perch:if id="catDepth" match="neq" value="0">
<li style="margin-left: <perch:category id="catDepth" type="hidden" />0px;">
    <h4><perch:category id="catTitle" type="smarttext" label="Title" required="true" /></h4>
    <perch:category id="catSlug" type="slug" for="catTitle" suppress="true" />
    <perch:category id="desc" type="textarea" label="Description" editor="markitup" markdown="true" size="s" />
</li>
</perch:if>
<perch:after></ul></perch:after>

The addition is the catDepth if statement surrounding the main detail.

Great solution, Duncan! I predict this will come in handy one day.