Filtering by Multiple Topics
Permalink
Having scoured the Forum for pointers on how to best approach multiple filters it seems this is not something which is easily resolvable or likely to be added in the near future.
I tried creating a CustomPageList class to extend the PageList functionality as suggested herehttps://www.concrete5.org/community/forums/customizing_c5/how-to-pag... but I just get errors which suggest the database structure may have changed since this post?
Updating an existing site (v8.2.1) and with a deadline pending I needed to get a solution so I have set up a custom template which filters the $pages Page List object on a pages loop for selected topics posted before re-indexing the $pages array.
This is a terribly hacky and inefficient way of handling as it is looping through the page list twice it but works for now. My question is would it be possible to improve on this by carrying this out in the controller so the page list is only generated once rather than generated and then filtered in the custom template?
I can see the action_filter_by_topic section and can see the $treeNodeID comes from the URL e.g. "/topic/1/topic1" but could this be adapted to accept multiple topics along the lines of e.g. /topic/1/topic1/2/topic2? How do I find out where the URL is parsed and $treeNodeID gets generated?
Or is this completely the wrong approach and should I be looking elsewhere for a better solution. Apologies for the waffling and vague question but hopefully someone will be able to point me in the right direction for a better solution.
Thanks
Paul
I tried creating a CustomPageList class to extend the PageList functionality as suggested herehttps://www.concrete5.org/community/forums/customizing_c5/how-to-pag... but I just get errors which suggest the database structure may have changed since this post?
Updating an existing site (v8.2.1) and with a deadline pending I needed to get a solution so I have set up a custom template which filters the $pages Page List object on a pages loop for selected topics posted before re-indexing the $pages array.
$selected = $_POST['selected-topics']; $i = 0; foreach ($pages as $page) { $topics = $page->getAttribute('topic'); foreach ($topics as $topic) { if (!in_array($topic->getTreeNodeID(), $selected)) { unset($pages[$i]); break; } } $i++; } $pages = array_values($pages);
This is a terribly hacky and inefficient way of handling as it is looping through the page list twice it but works for now. My question is would it be possible to improve on this by carrying this out in the controller so the page list is only generated once rather than generated and then filtered in the custom template?
I can see the action_filter_by_topic section and can see the $treeNodeID comes from the URL e.g. "/topic/1/topic1" but could this be adapted to accept multiple topics along the lines of e.g. /topic/1/topic1/2/topic2? How do I find out where the URL is parsed and $treeNodeID gets generated?
public function action_filter_by_topic($treeNodeID = false, $topic = false) { if ($treeNodeID) { $topicObj = Topic::getByID(intval($treeNodeID)); if (is_object($topicObj) && $topicObj instanceof Topic) { $this->list->filterByTopic(intval($treeNodeID)); $seo = Core::make('helper/seo'); $seo->addTitleSegment($topicObj->getTreeNodeDisplayName()); } } $this->view(); }
Or is this completely the wrong approach and should I be looking elsewhere for a better solution. Apologies for the waffling and vague question but hopefully someone will be able to point me in the right direction for a better solution.
Thanks
Paul
If the topic is nested then the mysql query also needs to contain the parent name:
It is possible to grab the parent name within the selected topics loop:
ak_topicName LIKE '%||/topicParent/Topic1%||' OR ak_topicName LIKE '%||/topicParent/Topic2%||'
It is possible to grab the parent name within the selected topics loop:
foreach($topics as $topic) { $topicObj = TopicTreeNode::getByID($topic); $parent = $topicObj->getTreeNodeParentID(); $parentObj = TopicTreeNode::getByID($parent); $sqry .= "ak_topicName LIKE '%||/". $parentObj->getTreeNodeDisplayName()."/".$topicObj->getTreeNodeDisplayName()."%||' OR "; }
Filtering the page list after it was created was not ideal for a number of reasons including performance and it also ruined pagination!!
In the documentation there is a section on Advanced techniques using the getQueryObject() to generate custom where clause:
I had seen a similar approach to filtering by multiple tags (sorry can't remember where fromto add a link and credit). So I used
with a single topic
to look at the query being generated.
I was then able to build my own query up by looping through an array of selected topics and adding OR . Remembering to remove the final trailing OR to stop a database error.
Hopefully this will be of use to someone.
Thanks
Paul