Nico Knoll

Module want: Related pages

72 posts in this topic

Sorry I probably wasn't clear, I would like to limit to the top 4 related pages. If I use your suggestion won't it limit before sorting?

Share this post


Link to post
Share on other sites

Aahh, now I understand. Apologies. I think array_slice might be what you need.

arsort($related_id);

$related_id = array_slice($related_id, 0, 4);

foreach($related_id as $key => $val){
$rp = $pages->get($key); ?>
<a href="<?=$rp->url;?>"><?=$rp->title;?><br><?
}

That should limit the array $related_id to just the first 4 entries, which I think are the highest scoring after the arsort().

Share this post


Link to post
Share on other sites

Hmmm

Before I added the array_slice I got all the related pages correctly, when I add the array_slice I get 4 results but they are the current page, the home page,  /processwire/ and  /processwire/page/

foreach ($page->tags as $tags) {
    $tag           = $sanitizer->selectorValue($tags->title);
    $related_pages = $pages->get("/products/")->find("tags.title=$tag");
    foreach ($related_pages as $related) {
        if ($related->id != $page->id)
            $related_id[$related->id]++;
    }
}
arsort($related_id);
foreach ($related_id as $key => $val) {
    $rp = $pages->get($key);
foreach ($page->tags as $tags) {
    $tag           = $sanitizer->selectorValue($tags->title);
    $related_pages = $pages->get("/products/")->find("tags.title=$tag");
    foreach ($related_pages as $related) {
        if ($related->id != $page->id)
            $related_id[$related->id]++;
    }
}
arsort($related_id);
$related_id = array_slice($related_id, 0, 4);
foreach ($related_id as $key => $val) {
    $rp = $pages->get($key);

???

Share this post


Link to post
Share on other sites

I think the whole example from further up the thread could just be shortened as there are errors in it. Well, unnecessary sanitisation anyway.

For one, you don't have to sanitise $tags->title as $pages->find("tags=$page->tags") is sufficient as it matches page IDs stored in the tags field across the site with the tags in the current page.

Here's my shortened version of your latest post:

foreach ($pages->get("/products/")->children("tags=$page->tags, id!=$page->id, sort=-sort, limit=4") as $related) { // In one line I think we've done it all :)
    echo "<a href='$related->url'>$related->title</a><br />";
}

It may not work because I've not tested it, but it's worth a go :)

I assumed the products were manually sorted and you wanted the last 4 not the first 4, hence the -sort, but if you want the latest you could to -id as newer pages will have higher IDs.

I think if you do the sort before limiting the number it returns it will do the query in that order.

id != $page->id will exclude the current page from the results. If the $page is a product though, you might have simply been able to do something like foreach ($page->siblings(<selector goes here>)... and so on, like this:

foreach ($page->siblings("tags=$page->tags, sort=-sort, limit=4") as $related) {
    echo "<a href='$related->url'>$related->title</a><br />";
}
 

Share this post


Link to post
Share on other sites

Thanks for that Pete, I agree that approach is simpler but it is not a simple sort I am after. To quote an earlier post I want it to look for pages with the same tags and the more tags are shared, the more "related" the other page is, thus getting it further up on the list.

So I tried the snippet apeisa posted and it works! I adapted it for my needs obviously. Thanks everybody for your help. The answer I was looking for was here all along

:rolleyes: 

foreach($page->tags as $tag) {
  $related_pages = $pages->find("template=article, tags=$tag");
  foreach($related_pages as $related) {
    if($related->id != $page->id) $related_id[$related->id]++;
  }
}

arsort($related_id);
// We limit it to three related pages at max
$related_id = array_slice($related_id, 0, 3, true);

foreach($related_id as $key => $val){
  $rp = $pages->get($key);
2 people like this

Share this post


Link to post
Share on other sites

Ah, sorry - I completely misunderstood that bit.

Glad it's sorted though.

Share this post


Link to post
Share on other sites

Actually there is one more thing, how can I make it conditional so it only outputs content if there are in fact related pages?

foreach($page->tags as $tag) {
  $related_pages = $pages->find("template=article, tags=$tag");
  foreach($related_pages as $related) {
    if($related->id != $page->id) $related_id[$related->id]++;
  }
}

arsort($related_id);
// We limit it to three related pages at max
$related_id = array_slice($related_id, 0, 3, true);

foreach($related_id as $key => $val){
  $rp = $pages->get($key);
echo
//Conditional stuff here...

Share this post


Link to post
Share on other sites

If I understand correctly, would counting related_id work?

if(count($related_id)>0){
1 person likes this

Share this post


Link to post
Share on other sites

I have tried that but I am not sure where to put it, I still get the conditional content regardless. Here is my code snippet, I know it's messy with all those unnecessary echos...

<?php
foreach ($page->tags as $tag) {
    $related_pages = $pages->find("template=product|product-2, tags=$tag");
    foreach ($related_pages as $related) {
        if ($related->id != $page->id)
            $related_id[$related->id]++;
    }
}

arsort($related_id);
// We limit it to 4 related pages at max
$related_id = array_slice($related_id, 0, 4, true);

foreach ($related_id as $key => $val) {
    $rp    = $pages->get($key);
    $first = $rp->gallery->first();
    $thumb = $first->gallery_image->size(780, 600);
    echo "<div class='col-27";
    foreach ($rp->tags as $tag) {
        echo " {$tag->name}";
    }
    echo "'>";
    echo "<article class='project'>";
    echo "<figure class='project-thumb'>";
    echo "<img src='{$thumb->url}' alt='project-1'>";
    echo "<figcaption class='middle'>";
    echo "<div>";
    echo "<a href='{$rp->url}' class='icon circle medium'><i class='fa fa-link'></i></a>";
    echo "<p style='color:white'>{$rp->page_heading}</p>";
    echo "</div>";
    echo "</figcaption>";
    echo "</figure>";
    
    echo "<header class='project-header'>";
    echo "<h4 class='project-title'><a href='{$rp->url}'>{$rp->title}</a></h4>";
    echo "</header>";
    echo "</article>";
    echo "</div>";
}
?>

Share this post


Link to post
Share on other sites

Well I am not sure I understand - the stuff inside the 

foreach ($related_id as $key => $val) {

will only get displayed if the $related_id array has entries in it so perhaps you need to figure out why there are page ids in that array in the first place if there are no related pages.

EDIT: I had some code here that I thought made sense, but then realized it didn't :)

1 person likes this

Share this post


Link to post
Share on other sites

Arrrrr, it was my own stupidity. The content was outside the conditional. You were exactly right there was nothing in the array so why should it get displayed?

Thanks!

:grin:

Share this post


Link to post
Share on other sites

Hello. I found this topic looking for some ideas about similar pages. Presently I am working on a cooking website and am looking at how to organize a block of similar recipes in the recipe view. What I have so far is a parent page Categories in which I am creating the child pages for every category. Then in the recipe template I have a field (recipe_category) to select one or multiple categories the recipe belongs to. If the recipe had only one category assigned, it would have been easy to get the result checking if there are others within the selected category however what would be the approach if a recipe belongs to multiple cats?

I know I could use the recipe tags too for the sorting and in this case I could implement the tags weight solution provided in earlier posts however how would you suggest to find similar pages which would basically hold an array of recipe_category?

 

Share this post


Link to post
Share on other sites

Hi @MilenKo

Maybe you can rely on some additional field like "ingredients" when a recipe belongs to multiple categories? 

Share this post


Link to post
Share on other sites

@Zeka I thought about that too, however with similar products you can make completely different results sometimes so it won't be a match. Example would be using almonds/almond flour and coconut oil to pan-fry meat or make a cake :)

Share this post


Link to post
Share on other sites

@MilenKo

$recipesCategoriesSelector = $page->recipe_categories->implode("|");
$related = $pages->find("template=recipe, recipe_categories={$recipesCategoriesSelector}, sort=random, limit=4);

 

 

1 person likes this

Share this post


Link to post
Share on other sites

Hello. I have 3 templates:  category  sub-category  partner

I can output the template "partner" from a sub-category!
But if there arent't 3 partners in that sub-catgory I want to get the others from the parent category template.

Thank you

                $morep = $page->parent->children("template=partner, id!=$page->id, limit=3, sort=random");
                foreach($morep as $a) {
                  $firstimage = $a->images->first();
                  $thumb = $firstimage->size(400, 200);
                  echo "<li class='item'>
                      <div class='img_box'>
                         <a href='$a->url' title='$a->title'>
                        <img src='$thumb->url' alt='$a->title' width="400" height="200">
                        </a>
                      </div>
                  <div class='featured_title_postcustom'>
                          <div class='caption_inner'>
                              <a href='$a->url'><h4>$a->title</h4></a>
                              <div class='post_date {$a->parent->parent->style_color}'><em>
                              <a href='$a->url' title='$a->title'> {$a->parent->parent->title} {$a->parent->title} </a></em></div>
                          </div>
                  </div>
                    </li>";
                 }


-- My sitemap Pages Templates --

Category
  -sub-category
    -partner

Category
  -sub-category
    -partner

Share this post


Link to post
Share on other sites
$morep = $featured = $page->siblings("template=partner, limit=3, sort=random", false);
if($morep->count() < 3) { $morep->import($page->closest("template=category)->children("template=partner, id!=$page->id, limit=3, sort=random") }

 

1 person likes this

Share this post


Link to post
Share on other sites

@Zeka Will try your suggestion later on today and share if that works fine. Because I was thinking of another way to organize what is needed, but I don't want to flood the topic. Basically instead of finding matching pages I thought to add a field with PageSelect and pick up manually recipes that would have similarities. Doing so is not an automated process but in my case would allow to be used for drinks matching the recipe or other recipes that you would prefer to suggest (versus the automated). 

It is always good to have options so I appreciate your suggestion. Now I have an option to provide similar pages by tags, by "category" and manually select so it could even be set in the admin as a drop down box to choose which way to go ;)

1 person likes this

Share this post


Link to post
Share on other sites

@Zeka I tried your suggestion and I am closer but the result of the query is not what is needed: 

Here is the code I used with a tiny modification to match the correct field names:

$recipesCategoriesSelector = $page->recipe_category->implode("|");
$related = $pages->find("template=recipes-inner, recipe_category={$recipesCategoriesSelector}, limit=3");
foreach($related as $similar_recipes) { 
echo $similar_recipes->title;
}

The result I see instead of having the title of the recipe is the text Categories which is the name of the parent that I used to add child pages as categories.

Any ideas what is wrong?

Share this post


Link to post
Share on other sites

Could you please share your tree view for these pages.

Share this post


Link to post
Share on other sites

== Home
== Categories (template=categories)
== == Category 1 (template=categories)
== == Category 2 (template=categories)
== Recipes (template=recipes)
== == Recipe 1 (template=recipes-inner)
== == Recipe 2 (template=recipes-inner)
== Tags (template=tags)
== == Tag 1 (template=tags)
== == Tag 2 (template=tags)

So each recipe could have multiple categories or a single if needed. With the earlier provided code, $related is equal to the id of Categories page but not to the recipes containing the selected categories, hence $related->title shows "Categories"

Edited by MilenKo
Added template names after the corrections

Share this post


Link to post
Share on other sites

@Zeka I think I found the issue as the query seemed perfectly right but was showing strange results. So I went back to check every template and found out that Categories page had assigned recipe-inner as template instead of categories. This would explain the strange result.

Edit: After applying the proper templates as per the tree above, the query returns no results. I even deleted all the categories child pages and added them back to every recipe to make sure that at least a few of them would match with others, but still nothing.

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.