Jump to content
stanoliver

pagination with categories

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")); ?>

Share this post


Link to post
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)

 

Share this post


Link to post
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.

Share this post


Link to post
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.

Share this post


Link to post
Share on other sites

Yes, my categories are pages and the url-structure example.com/categories/cars/ but I am not sure what you mean with page references. I have adjusted the your id=1192 to the id of page "categories"

Share this post


Link to post
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")); ?>

Share this post


Link to post
Share on other sites

@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.

Share this post


Link to post
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

Share this post


Link to post
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");

 

Share this post


Link to post
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.

Share this post


Link to post
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"

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Peter Troeger
      Hello Community 🙂
      Has anyone ever tried having multiple elements on one page that get their info with $pages->find('selector, limit=n') and tried using pagination on one of these elements without effecting the other?
      I have a slider on a page where I display content with pagination. But when I go to page two, the slider content also goes to page two, which I don't want it to do 🙂
      Any tips are greatly appreciated!
      Thanks!
      -Peter
    • By Peter Troeger
      Hello 🙂
      I have set up pagination on a mulitlanguage site.
      I've done this before, but this time I have a problem I can't solve.
      Pagination is activated on 'parent-template' and 'child-template' just to be sure 🙂
      This is my code:
      $children = $page->children('limit=1'); foreach($children as $child) { $title = $child->title; echo $title; } echo $children->renderPager(); The navigation is output correctly and the link look correct as well 'parent-page/page2/'.
      But when I click the link, the site seems to redirect back to 'parent-page/
      Any help would be greatly appreciated 🙂
      - Peter
    • By MateThemes
      Hello everyone!
      I have a problem with pagination. I have following code:
      <div class="uk-section"> <?php $results = $pages->find("template=gallery, limit=10, sort=title"); $pagination = $results->renderPager(); echo $pagination; echo "<ul class='uk-pagination uk-flex-center'>"; foreach($results as $result) { echo "<li><a href='{$result->url}'>{$result->title}</a></li>"; } echo "</ul>"; echo $pagination; ?> </div> Which works fine. And this markup results in following html code:
      <div class="uk-section"> <ul class='uk-pagination uk-flex-center'> <li> <a href='/galerie-bisheriger-projekte/'>Galerie bisheriger Projekte</a> </li> <li> <a href='/galerie-bisheriger-projekte/galerie-1/'>galerie-1</a> </li> </ul> </div> But instead of "Galerie bisheriger Projekte" and "galerie-1" I want to have a number.
      And as last question, how can I add a previous and next button?
      Thanks for your help!
    • By Liam88
      Hi all,
      Quick question as I haven't found anything from my Googling. 
      I have a blog on the site which utilises pagination. On the standard blog page I have a custom header which has featured posts.
      Below that I then have recent posts like mosts blogs.
      Now if i click to page two or three I want the header to disappear and just show a continuation of the standard posts.
      I'm not sure how to go about this so any direction would be helpful.
      Thanks
    • By usualCommission
      Hey everyone,
      I'm pretty experienced with pagination and haven't seen this before. I have my pages pulled using $pages->find, which is working fine however using renderPager() generates pagination where the links do not work. Here are some details.
      All templates needing pagination have pagination enabled in the admin. URL Segments are not enabled. Clicking on the "Next" or numbered links merely reloads the current page. The link href values are properly being output with the urls being /page2, /page3, /page4, etc. Manually entering the paginated urls has the same effect of reloading the current page with no new content. Pages are being returned from the ->find function properly and with the proper limit. A few other details:
      ProcessWire v3.0.98 Multi-language is enabled, 2 languages implemented. Pagination does not work on either language Have very few modules installed (few enough to list), none of which I could see interfering: ProFields, ProDrafts, ListerPro, DB Backups, Cronjob DB Backup, Upgrades, Upgrade Checker, Force Password Change, Markup Sitemap XML I'm stumped. For the sake of being overly-thorough, here's the code:
      <?php $articleTemplates = [ 'template_news_article', 'template_news_video', 'template_news_press_release' ]; $searchParams = [ 'template=' . implode('|', $articleTemplates), 'sort=-published', 'limit=' . $pages->get('template=template_news')->list_count ]; $articles = $pages->find(implode(',', $searchParams)); echo $articles->renderPager(); ?>  
×
×
  • Create New...