Jump to content
onjegolders

Simple categories filtering

Recommended Posts

I've been reading up on a few posts on categories but I'm struggling to get them working.

I saw a video from PW1

and the example seems nice and simple:

Output the categories, click one and the list of entries gets filtered.

I tried to replicate that but no joy. I can't seem to understand how Ryan can output $page->categories from his page when really the categories are surely part of children()?

Is it really possible to filter categories of events or news this simply? I've seen other examples in the forums which look much more complex (urlSegments and the like).

I currently have my category page set up as a child of home, and categories as its children.

Before seeing that video, I had managed to output the categories like this:

<div id="events_index_side">

<?php if ($pages->find("template=category")) { ?>

<div class="events_index_side_box">

<h5 class="page_header">By category</h5>

<ul>
<?php $categories = $pages->find("template=category");
foreach ($categories as $category) { ?>

<li><a href="<?php echo $page->url . $category->name; ?>"><?php echo $category->title; ?></a></li>

<?php }
?>
</ul>

</div><!-- /.events_index_side_box -->

<?php } ?>

but using this method, I'm not quite sure how I can get the page to reload with just those categorised entries?

Would appreciate if anyone could give me a shove in the right direction. Thanks.

Share this post


Link to post
Share on other sites
if ($pages->find("template=category"))

The above will never resolve to false, so doesn't do anything. That's because find() returns a PageArray(). Think of it like a bottle that might have beer in it. An empty beer bottle is still a beer bottle. So you have to check if there's anything in it:

$categories = $pages->find("template=category"); 
if(count($categories)) {
   // there are categories
   foreach($categories) {
       // output category
   }
}

I suggest using a separate 'category' template to handle the display of a given category (rather than trying to do it all in your 'categories' template). Here's the code you might do it with in your category template. This assumes the categorized entries have a field called "categories"

$entries = $pages->find("categories=$page"); 
if(count($entries)) {
   echo "<ul>";
   foreach($entries as $entry) {
       echo "<li><a href='{$entry->url}'>{$entry->title}</a></li>";
   } 
   echo "</ul>";
} else {
   echo "<p>No entries in this category.</p>";
}
  • Like 1

Share this post


Link to post
Share on other sites

The above will never resolve to false, so doesn't do anything. That's because find() returns a PageArray(). Think of it like a bottle that might have beer in it. An empty beer bottle is still a beer bottle. So you have to check if there's anything in it:

$categories = $pages->find("template=category");
if(count($categories)) {
// there are categories
foreach($categories) {
	// output category
}
}

I suggest using a separate 'category' template to handle the display of a given category (rather than trying to do it all in your 'categories' template). Here's the code you might do it with in your category template. This assumes the categorized entries have a field called "categories"

$entries = $pages->find("categories=$page");
if(count($entries)) {
echo "<ul>";
foreach($entries as $entry) {
	echo "<li><a href='{$entry->url}'>{$entry->title}</a></li>";
}
echo "</ul>";
} else {
echo "<p>No entries in this category.</p>";
}

Thanks Ryan, that makes it clearer, though I'm still unsure what I should be doing on my events "index" page.

On the left I display all the events and in the sidebar I ideally wanted to list the categories and then on click, filter the entries (I suppose at events/category_name).

Sorry for being slow, just not quite sure how to link this up.

On your video example, you only seemed to have a small bit of code in one template which did all the magic!

Share this post


Link to post
Share on other sites
On the left I display all the events and in the sidebar I ideally wanted to list the categories and then on click, filter the entries (I suppose at events/category_name).

If you want your events index to list all the categories, you could just do thi:

$categories = $pages->find("template=category, sort=name");

foreach($categories as $c) echo "<p><a href='{$c->url}'>{$c->title}</a></p>";

If you want to use URL segments to filter the listing of events by category, you could use URL segments with a URL structure like /events/category/cheese/. Then your events index could look for it like this:

if($input->urlSegment1 == 'category' && $input->urlSegment2) {
   $name = $sanitizer->pageName($input->urlSegment2);
   $category = $pages->get("template=category, name=$name"); 
   if($category->id) {
       $events = $pages->find("template=event, categories=$category"); 
       foreach($events as $event) echo "<p><a href='{$event->url}'>{$event->title}</a></p>"; 
   }
}
  • Like 2

Share this post


Link to post
Share on other sites

Thanks, have spent this morning trying to get this to work but I'm just not managing it unfortunately.

I've gone down the include route so that now, my event index page looks like this:

<?php include("./header.inc"); ?>

<?php if ($input->urlSegment1 != "") {
include ("./categories.inc");
} else { ?>

<div id="events_index_wrap" class="bg_gradient">

<div id="events_index_main">

<h3 class="page_header">Upcoming Events</h3>

<?php
$entries = $pages->find("template=event, sort=date");
$count = 0;

foreach ($entries as $event) {
$count++;
$class = "event_box";
if (0 == $count % 2) { $class .= " event_box_second"; }
?>

<div class="<?php echo $class; ?>">

<div class="event_box_text">
<h2><a href="<?php echo $event->url; ?>"><?php echo $event->title; ?></a></h2>
<h5><?php echo $event->date; ?></h5>
</div><!-- /.event_box_text -->
<div class="clear"></div>

<?php if ($event->images) {
$img = $event->images->first()->size(220,165);
?>
<a href="<?php echo $event->url; ?>"><img src="<?php echo $img->url; ?>" width="<?php echo $img->width; ?>" height="<?php echo $img->height; ?>" alt="<?php echo $entry->title; ?>" class="med_frame" /></a>
<?php } ?>

</div><!-- /.event_box -->

<?php }
?>

</div><!-- /#events_index_main -->

<div id="events_index_side">


<div class="events_index_side_box">

<?php if (count($pages->find("template=category"))) {
$category = $pages->find("template=category");
?>
<ul>
<?php foreach ($category as $cat) { ?>
<li><a href="<?php echo $page->url . $cat->name; ?>"><?php echo $cat->name; ?></a></li>
<?php } ?>
<?php } ?>

</div><!-- /.events_index_side_box -->

</div><!-- /#events_index_side -->

<div class="clear"></div>

</div><!-- /#events_index_wrap -->

<?php } ?>

<?php include("./footer.inc"); ?>

So on the category list, I tack on the category name to the url and if there's a URL segment it includes the categories include, which looks like:

<div id="events_index_wrap" class="bg_gradient">

<div id="events_index_main">

<h3 class="page_header">Upcoming Events - <?php echo $input->urlSegment1; ?></h3>

<?php
$name = $sanitizer->pageName($input->urlSegment1);
echo "<h1>$name</h1>";

$entries = $pages->find("template=event, categories=$name, sort=date");
$count = 0;

foreach ($entries as $event) {
$count++;
$class = "event_box";
if (0 == $count % 2) { $class .= " event_box_second"; }
?>

<div class="<?php echo $class; ?>">

<div class="event_box_text">
<h2><a href="<?php echo $event->url; ?>"><?php echo $event->title; ?></a></h2>
<h5><?php echo $event->date; ?></h5>

</div><!-- /.event_box_text -->
<div class="clear"></div>

<?php if ($event->images) {
$img = $event->images->first()->size(220,165);
?>
<a href="<?php echo $event->url; ?>"><img src="<?php echo $img->url; ?>" width="<?php echo $img->width; ?>" height="<?php echo $img->height; ?>" alt="<?php echo $entry->title; ?>" class="med_frame" /></a>
<?php } ?>

<?php $categories = $event->categories; foreach ($categories as $cg) { ?>
<h6><?php echo $cg->name; ?></h6>
<?php } ?>

</div><!-- /.event_box -->

<?php }
?>

</div><!-- /#events_index_main -->

<div id="events_index_side">


<div class="events_index_side_box">

<?php if (count($pages->find("template=category"))) {
$category = $pages->find("template=category");
?>
<ul>
<?php foreach ($category as $cat) { ?>
<li><a href="<?php echo $page->url . $cat->name; ?>"><?php echo $cat->name; ?></a></li>
<?php } ?>
<?php } ?>

</div><!-- /.events_index_side_box -->

</div><!-- /#events_index_side -->

<div class="clear"></div>

</div><!-- /#events_index_wrap -->

My issue is that I'm pretty sure that the category name is matching the urlSegment but when I choose a category the list comes up empty. I've thought of possible reasons (lower/upper case categories?), I've also tried to pass a variable to the current category but not to sure how to get that working before looping through the entries...

If anyone has any idea, that would be much appreciated, thanks.

Share this post


Link to post
Share on other sites

This is one of those moments when I question what I'm doing with my life! Spend 7 hours today trying to figure out this one problem (sometimes I really think I would pay for commercial support ;))

Seems I should have been setting a $category variable and checking for name=$name (so essentially was missing a step) I must have spent about a million hours trying to figure that out...

One thing I can't seem to figure out though is how to only show links to categories that have been used once or more. Currently it is showing all categories, even if they're empty. The tiny logical part of my brain is saying that I should be referencing events and not categories

Something like:

$cats = $pages->find("template=event")->categories;

But can't seem to figure it out

Share this post


Link to post
Share on other sites

If you are displaying categories and want to exclude any that don't have any events attached, then you could do this:

$categories = $pages->find("template=category"); 
foreach($categories as $category) {
   $numEvents = $pages->count("template=event, categories=$category"); 
   if($numEvents > 0) {
       // display category
   } else {
       // don't display category
   }
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By carlitoselmago
      I'm building a fieldtype/inputfield to visually select a grid like Bootstrap since it's the first time coding such thing, I'm basing my code in FieldtypeColorPicker since the base structure is the same, a graphical UI helper to finally output a string as value.
      The problem is I try to save the value as something like "1,2,3" referencing the index of each column selected but it gets converted as an int value so "1,2,3" becomes "1" if input random text it gets converted as "0".
      Here is the code:
      https://github.com/carlitoselmago/FieldtypeGridSpace
      Here's an screenshot of how it looks

    • By Bacelo
      Hi there,
      I have a bit of trouble on filtering correctly some event pages by some selectors...
      I do have the following 2 date fields:
      - start date (fieldname = date)
      - end date (fieldname = enddate)

      Some events are a single day event (only start date) - some are a multi day event (end date).
      Past single day events should not show up.
      Current multi day events should show up (even if start day is in the past, but end date is future).
      So I have the following selector:
      if ($standort == '') { $termine = $page->children("sort=date, limit=10, (date>=today, enddate=''), (enddate>=today)"); } else { $termine = $page->children( "(standort_reference~=$standort), (standort_alle=1), (date>=today, enddate=''), (enddate>=today), sort=date, limit=10"); } This selector
      $termine = $page->children("sort=date, limit=10, (date>=today, enddate=''), (enddate>=today)"); works fine, but the follwing does not work (all past entries are also shown):
      $termine = $page->children( "(standort_reference~=$standort), (standort_alle=1), (date>=today, enddate=''), (enddate>=today), sort=date, limit=10"); I have no clue what I'm missing - any ideas?
    • By bramwolf
      Hi Guys,

      I found that my site is producing this notice on the front end, even when $config->debug = false and also when admin is
      not even logged in. How do I keep the site from displaying this message to front end users? The notice is about a few vars
      being tested, which in this case aren't defined, how would I stop that from happing all together when testing vars? if I for instance
      wrap the $discountCode = blabla in a if($order) { ...  } statement than I'm again testing for $order which isn't a object in this case
      which throws another notice..

      This is the notice:


      Here is my current code:
      // PAD DISCOUNT CODE HOOK // First we see if we have active discount code if ($this->session->orderId) { $order = $this->pages->get($this->session->orderId); } if($product->geen_korting == 1) { $nodisc = $product->geen_korting; } else { $nodisc = $product->parent->geen_korting; } $discountCode = $this->sanitizer->selectorValue($order->pad_discount_code); $dc = $this->pages->get("template=paddiscount, title=$discountCode"); if ($dc->id) { if ($nodisc) { $discount = 0; } elseif ($dc->pad_percentage) { $discount = $newprice * ($dc->pad_percentage / 100); } } $event->return = $newprice - $discount;
      Thanks in advance 🙂
    • By shadowkyogre
      [EDIT]: After sitting down and planning out my site according to the ragged hierarchy information, I settled on the following schematics.
      /$world/$template/$content_of_template_type/... for my pretty URLs /roster/$character for my characters a generic Repeater field with depth on most content types for custom positions for child pages to connect to instead of it directly a few Repeater fields on each content that have (PageReference[1], other fields) to establish associations A few FieldsetGroups to help me manage the fields that I needed to copy across a bunch of content types. Kept the original post below for context and tagged the OP for searchability.
      ---
      Hi everyone! I'm working on a personalized worldbuilding wiki to host my art and story stuff.
      Right now my site architecture looks like...
      /$world/cosmology/$cosmology /$world/locations/$location /$world/factions/$faction /$world/history/$history /$world/species/$species /roster/$character So far the layout works, but there's one problem. I need to make sub-sections for an organization. Organizations can appear under cosmology, locations, and factions. Sounds straightforward until... I run into the problem of figuring out how to represent subfactions.
      Key factors in this are...
      Characters should be able to be part of multiple organizations Characters should have an explicit role assigned to their membership. Character pages should be able to query the organization pages to display their ranks across organizations. Editing an organization's hierarchical layout should be visible while editing the root organization page. From what I've read of the ProcessWire documentation, the best use case for each way of representing the organization's subsections are...
      Child Pages:: Works best for menu presentation and dedicated editing. PageTables:: Works if you want control over where to place the PageTable fields, but requires opening a modal for the pages you want to edit. It's also kind of like normal pages. Repeaters:: Works great for inline editing and easy control over hierarchy, but the page urls become obscure. Sections in the body field:: Works for copypasting from my note files. But it doesn't expose relationships for easy querying. It looks like my best case for this is child pages since it allows displaying suborganization in the URL easily. But also I lose out on quickly reordering and editing the child pages. Any advice for people running into similar use cases?
    • By a.masca
      Goodmorning everyone,
      sorry for the inconvenience but I have a problem that I can't find in any other post.
      Strange things happen on a site:
      - despite everything being configured correctly (as already done in dozens of other sites) only superusers can create new pages
      - if I insert in a selector "include = all" the result is always 0
      - I should restore a series of pages incorrectly inserted in the trash, but I cannot select them with the selector "status = Trash"
      Some idea?
      Thanks so much for your valuable support.
×
×
  • Create New...