Jump to content

pagination with categories


stanoliver
 Share

Recommended Posts

Good morning everyone!

I have a growing number of posts about cars, bikes, airplanes, etc. 

The following code (below) just works fine and returns only the posts of the category=cars as I desired together with pagination.

In my url I have for example /categories/cars/car1 or /categories/bikes/bike1

I do want to filter my posts not only with ... category=cars ... but also with category=bikes or category=airplanes and at best:

If my url is /categories/bikes/ then ... category=cars ... should be overwritten or replaced by ... category=bikes ... 

If my url is /categories/airplanes/ ... then the filter should be ... category=airplanes ... (I know a work around by creating almost identical templates where I could just change the "category=cars" part of my code but that's comes of a prize by repeating a lot of identical code and is not a good habit). In the documentation I read something about the "has_parent" selector but I could not get to work it related to the urls mentioned above.

<?php foreach ( $results = $pages->find('id>1, template=templateblogpost, category=cars, limit=5, sort=-postdate') as $post ??>
<!-- Blog entry -->
<div class="g8-card-4 g8-margin g8-white">
<!--<img src="/g8images/bridge.jpg" alt="Norway" style="width:100%">-->
<div class="g8-container">
<h3><b><?= $post->title; ?></b></h3>
<h5>Datum: <span class="g8-opacity"><?= $post->postdate; ?></span></h5>
</div>
 
<div class="g8-container">
<p><?= $post->posteditor; ?></p>
<div class="g8-row">
<div class="g8-col m8 s12">
<p>
<a href="<?= $post->url; ?>"><button class="g8-button g8-padding-large g8-white g8-border"><b>Details lesen &raquo;</b></button></a>
</p>
</div>
<div class="g8-col m4 g8-hide-small">
<!--<p><span class="g8-padding-large g8-right"><b>Comments &nbsp;</b> <span class="g8-badge">2</span></span></p>-->
</div>
</div>
</div>
</div>
<!-- END BLOG ENTRIES -->
<?php endforeach; ?>
 
<? echo $results->renderPager(array(
'nextItemLabel' => "rückwärts",
'previousItemLabel' => "vorwärts")); ?>
Link to comment
Share on other sites

7 minutes ago, dragan said:

Just use URL segments.

Hi @dragan, I have read about url segments before but I have no idea how to implement it in my code above. Also I am not sure if url segments still work if new categories will be added by an end user of the cms (at the moment I just have the categories cars, bikes, planes, ...).

Is there no easy way with a switch or if statement just to check what is the parent url segment (/categories/car/) -> return ... category=cars

check case: /categories/bikes/ -> return ... category=bikes

If I just wanted a working solution and would have 5 categories for example than I would just my code from above 4 more times to 4 new templates and all is fine (but bad practise because all code would be identical and only differ by one word (the category itself)

 

Link to comment
Share on other sites

 

// we are only using 1 URL segment, so send a 404 if there's more than 1
if(strlen($input->urlSegment2)) throw new Wire404Exception();

$segment = $sanitizer->pageName($input->urlSegment1);
$categories = $pages->get(1192)->children; // 1192 = id of parent holding my category pages
$allowed = array();
foreach($categories as $cat) {
    $allowed[] = $cat->name;
}
// does the URL segment match an existing category name?
if(!in_array($segment, $allowed)) {
    throw new Wire404Exception();
} else {
  $results = $pages->find("id>1, template=templateblogpost, category=$segment, limit=5, sort=-postdate");
   foreach ($results as $post) {
    // output each $post
  }
}
5 minutes ago, stanoliver said:

Also I am not sure if url segments still work if new categories will be added by an end user of the cms

If you do it like my above example (or similar), yes.

Link to comment
Share on other sites

8 minutes ago, stanoliver said:

The provided code gives an 404 not found 

What could be wrong?

You probably didn't adjust this line:

1 hour ago, dragan said:

$categories = $pages->get(1192)->children; // 1192 = id of parent holding my category pages

I assume each of your categories is a page, i.e. you are using page references.

Link to comment
Share on other sites

@Gideon So Hi Gideon, if I use the code you provided and replace "Do your thing here."

with echo 'Hi!';

everything works but I need that code work togehter with my code from above. My own code from above works also perfectly but I do not want to repeat myself in way like:

<?php foreach ( $results = $pages->find('id>1, template=templateblogpost, category=cars, limit=5, sort=-postdate') as $post ?>
<!-- Blog entry -->
<div class="g8-card-4 g8-margin g8-white">
<!--<img src="/g8images/bridge.jpg" alt="Norway" style="width:100%">-->
<div class="g8-container">
<h3><b><?= $post->title; ?></b></h3>
<h5>Datum: <span class="g8-opacity"><?= $post->postdate; ?></span></h5>
</div>

 

<div class="g8-container">
<p><?= $post->posteditor; ?></p>
<div class="g8-row">
<div class="g8-col m8 s12">
<p>
<a href="<?= $post->url; ?>"><button class="g8-button g8-padding-large g8-white g8-border"><b>Details lesen &raquo;</b></button></a>
</p>
</div>
<div class="g8-col m4 g8-hide-small">
<!--<p><span class="g8-padding-large g8-right"><b>Comments &nbsp;</b> <span class="g8-badge">2</span></span></p>-->
</div>
</div>
</div>
</div>
<!-- END BLOG ENTRIES -->
<?php endforeach; ?>

 

<? echo $results->renderPager(array(
'nextItemLabel' => "rückwärts",
'previousItemLabel' => "vorwärts")); ?>
 
//and now the same code again with "category=cars" replaced with "category=bikes"
 
<?php foreach ( $results = $pages->find('id>1, template=templateblogpost, category=bikes, limit=5, sort=-postdate') as $post ?>
<!-- Blog entry -->
<div class="g8-card-4 g8-margin g8-white">
<!--<img src="/g8images/bridge.jpg" alt="Norway" style="width:100%">-->
<div class="g8-container">
<h3><b><?= $post->title; ?></b></h3>
<h5>Datum: <span class="g8-opacity"><?= $post->postdate; ?></span></h5>
</div>
 
<div class="g8-container">
<p><?= $post->posteditor; ?></p>
<div class="g8-row">
<div class="g8-col m8 s12">
<p>
<a href="<?= $post->url; ?>"><button class="g8-button g8-padding-large g8-white g8-border"><b>Details lesen &raquo;</b></button></a>
</p>
</div>
<div class="g8-col m4 g8-hide-small">
<!--<p><span class="g8-padding-large g8-right"><b>Comments &nbsp;</b> <span class="g8-badge">2</span></span></p>-->
</div>
</div>
</div>
</div>
<!-- END BLOG ENTRIES -->
<?php endforeach; ?>
 
<? echo $results->renderPager(array(
'nextItemLabel' => "rückwärts",
'previousItemLabel' => "vorwärts")); ?>
Link to comment
Share on other sites

  • 5 weeks later...

@stanoliver, please use the Code button for blocks of code you insert in the forum - your post above is almost unreadable.

2019-06-24_133640.png.8017095c9d78e077fd6fff60cce757c3.png

On to your problem...

As I understand it you are rendering a category page (cars, bikes, etc), and you have some posts which are tagged with these same category pages in a Page Reference field (a post is tagged with cars, bikes, etc). Therefore your selector would be:

$results = $pages->find("template=templateblogpost, category=$page, limit=5, sort=-postdate");

Note the double-quote marks around the selector string, so that the $page variable will be interpolated.

Then foreach() $results to output your markup.

Link to comment
Share on other sites

@Robin S What already work is (but only with repeating 3times almost identical code):

<?php foreach ( $results = $pages->find('id>1, template=templateblogpost, category=cars, limit=5, sort=-postdate') as $post ?>

do something

<?php endforeach?>

//////////////////////////////////////

<?php foreach ( $results = $pages->find('id>1, template=templateblogpost, category=airplanes, limit=5, sort=-postdate') as $post ?>

do something

<?php endforeach?>

////////////////////////////////////////

<?php foreach ( $results = $pages->find('id>1, template=templateblogpost, category=motorbikes, limit=5, sort=-postdate') as $post ?>

do something

<?php endforeach?>

What I would like to have:

Only one time the codeblock

<?php foreach ( $results = $pages->find('id>1, template=templateblogpost, category=$segment, limit=5, sort=-postdate') as $post ?>

do something

<?php endforeach?>

The problem is that I do not know what's the code related to $segment before the opening of <?php foreach ... ?>

I could imagine something like 

(*****)

if($segment->path == "/categories/segment/") {

<?php foreach ( $results = $pages->find('id>1, template=templateblogpost, category=$segment, limit=5, sort=-postdate') as $post ?>

do something

<?php endforeach?>

}

In short: 

1. The code should check in the url wich category is used and assign the variable $segment to it 

2. The code above (*****) should be executed with the right $segment

Link to comment
Share on other sites

@stanoliver, yes, I understand the objective. What's not clear is how your blog posts are identified as belonging to a particular category. If there is a blog post titled "My bike" and it is in the category of "bike", how do you connect category "bike" with post "My bike"? Probably it would help if you show a screenshot of your page tree, with both the post pages visible and the category pages visible.

Most commonly, developers structure their website so that they have a structure of category pages (using template "category" let's say), and then they have a Page Reference field (named "categories" let's say, with selectable pages "template=category") and they add this Page Reference field to the post template. Then for each post they select one or more category pages. That's what my previous post assumes. So that when you are viewing a category page on the front-end, that category page exists as the $page variable. And so if you want to find posts that have that category page assigned to them you search for them with this:

$results = $pages->find("template=templateblogpost, categories=$page, limit=5, sort=-postdate");

 

Another way that you might be connecting categories to posts is by a parent-child relationship. So the post pages are children of a category page that they belong to. This is okay but less flexible because it means that any post can only belong to one category. So if you found yourself needing to write a blog post "How to fix a bike rack to your car" you would have a problem because the post could only be in the bike category or the car category but not both.

But if you are in fact using a parent-child relationship you would use this selector on the category page (note change from $pages->find to $page->children):

$results = $page->children("template=templateblogpost, limit=5, sort=-postdate");

 

Link to comment
Share on other sites

Important: Using following selector works just perfect in my codeblock (xxx)

$results = $pages->find('id>1, template=templateblogpost, category=cars, limit=5, sort=-postdate'

and when I  go on repeating another codeblock with

$results = $pages->find('id>1, template=templateblogpost, category=airplanes, limit=5, sort=-postdate'

and the last codeblock with

$results = $pages->find('id>1, template=templateblogpost, category=motorcyles, limit=5, sort=-postdate'

all just works fine.

 

So one entire codeblock (xxx) wich just works perfect looks like:

<?php foreach ( $results = $pages->find('id>1, template=templateblogpost, category=cars, limit=5, sort=-postdate') as $post ??>
<!-- Blog entry -->
<div class="g8-card-4 g8-margin g8-white">
<!--<img src="/g8images/bridge.jpg" alt="Norway" style="width:100%">-->
<div class="g8-container">
<h3><b><?= $post->title; ?></b></h3>
<h5>Datum: <span class="g8-opacity"><?= $post->postdate; ?></span></h5>
</div>
 
<div class="g8-container">
<p><?= $post->posteditor; ?></p>
<div class="g8-row">
<div class="g8-col m8 s12">
<p>
<a href="<?= $post->url; ?>"><button class="g8-button g8-padding-large g8-white g8-border"><b>Details lesen »</b></button></a>
</p>
</div>
<div class="g8-col m4 g8-hide-small">
<!--<p><span class="g8-padding-large g8-right"><b>Comments  </b> <span class="g8-badge">2</span></span></p>-->
</div>
</div>
</div>
</div>
<!-- END BLOG ENTRIES -->
<?php endforeach; ?>
 
<? echo $results->renderPager(array(
'nextItemLabel' => "back",
'previousItemLabel' => "forward")); ?>

I also could use  the last codeblock (xxx) two more times and just replace in the "first line" "category=cars" by "category=airplanes". Another time (the third codeblock) would be identical and I only would replace "category=cars" by "category=motorcyles". Then I would have 3times an almost identical codeblock which only differs in one place: "category= " Repeating almost identical code is a bad habbit and therefore I need a variable like $segment so that I just can make everything work with one codeblock.

Maybe short in other words:

Before I can use something like $segment in my codeblock (xxx) I have to declare it before my block starts but I have no idea how to declare $segment. What I know is that my codeblock (xxx) works perfectly for a specific category.

Link to comment
Share on other sites

15 hours ago, Robin S said:

Another way that you might be connecting categories to posts is by a parent-child relationship. So the post pages are children of a category page that they belong to. This is okay but less flexible because it means that any post can only belong to one category. So if you found yourself needing to write a blog post "How to fix a bike rack to your car" you would have a problem because the post could only be in the bike category or the car category but not both.

But if you are in fact using a parent-child relationship you would use this selector on the category page (note change from $pages->find to $page->children):


$results = $page->children("template=templateblogpost, limit=5, sort=-postdate");

 

@Robin S 1. Yes, I am using a parent-child relationship and for the moment it would be enough even when a post can only be in one category.

2. The little snippet of Gideon

if($page->path == "/categories/cars/") {

Do your thing here.

}

is already totally fine and I do not need much more functionality. I only would need something like in (my own pseudocode comes now):

if($page->path == "/categories/$variable/") {

echo $variable->title;

}

If the url is

/categories/cars

the output should be all posts in category cars.

If the url is

/categories/airplanes

the output should be all posts in category airplanes

3. There would be no problem at all with all my mentioned code above if I only knew which are categories I will need in the future but I don't know that becaus the end user will be allowed to drop new childrend under the parent "categories"

 

Link to comment
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
 Share

×
×
  • Create New...