Jump to content
Nico Knoll

Module want: Related pages

Recommended Posts

DOH! Is it becuase 'tags' field is an asmSelect field and not a plain text field or textarea field?

Yes! But I'm not getting which one? The one on the articles I guess.

Try this:

$tagpage = $pages->find("template=tag, name=$tag")->first(); // get the page that is the tag page itself
$articles = $pages->find("template=article, tag=$tagpage"); // in case the tag on article is a page reference...

you would change the template name to whatever your's are. It's good practice to limit it if you do a $pages->find().

Or better do, if you can, $pages->get("/tags/")->find(...);

Share this post


Link to post
Share on other sites

Thanks Soma, I think I may be out of my depth :( but I'll try to comment and I hope I make sense...

I am not using a Template called tag or one called article, so I assume(?) I can delete those parts of the finds (also I changed:

tag=$tagpage

to

tags=$tagpage

otherwise I got an error).

With these changes I am no longer getting any errors, :) thank you! But I now see the code does not actually output anything -- I am trying to get out a list of tag names for the page being viewed and while I am getting no errors I'm also not seeing anything. I assume I need to do something with $related_articles, does that sound right so far do you think?

Share this post


Link to post
Share on other sites
I am trying to get out a list of tag names for the page being viewed
foreach($page->tags as $tag) {
 echo $tag->title;
}

Share this post


Link to post
Share on other sites

Alan, my code was just assuming things. Sorry if that confuses you.

But your tag pages, uses a template for sure. No way around that. :P

It's just that if you're doing a find over ALL pages in PW to look for a field with the name "mytag", it will not be as fast as if you limit the find to a template or even branch ( or it will possibly even find another page using the same name, thus creating problems) . That's all. It may doesn't matter in a 100 page website, but will with 1million pages. :)

Share this post


Link to post
Share on other sites

@apesia Thank you, so simple it's embarrassing.

@Soma NO problem with confusing me, it does me good to stretch my brain! :D And also I see now how limiting the search is a good idea (important indeed). And previously I didn't see your last line [$pages->get("/tags/")->find(...)] —my bad! I will go and try to implement that.

That together with @apesia's note on how to output tags only leaves me needing to work out how to link tags to an 'Other pages sharing this tag' type page. I will try to do that and only post here if I get stuck, er, which might just happen ;)

Thanks again!

Share this post


Link to post
Share on other sites

for example i've created related pages for a category, the lenght of a yacht

echo '<h3>Yachts Simili</h3>';

 //correlati lunghezza
 $lun = $page->lunghezza;
 $lunp = $lun+10;
 $lunm = $lun-10;
 $yachts = $pages->find('lunghezza>' . $lunm . ',lunghezza<' . $lunp . ', limit=3, sort=lunghezza');

Share this post


Link to post
Share on other sites

@buothz I think my related pages approach is different from yours, in case it's helpful I am going to write it up (eventually) when my site is tidied and up. Meantime, enjoy PW and good luck :)

Share this post


Link to post
Share on other sites

Hello,

I am going to resurrect this old post to share my "related pages" approach. It uses the described pages-as-tags and then looks for pages with the same tags. The more tags are shared, the more "related" the other page is, thus getting it further up on the list.

foreach($page->tags as $tags) {
$tag = $sanitizer->selectorValue($tags->title);
$related_pages = $pages->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); ?>
<a href="<?=$rp->url;?>"><?=$rp->title;?><br><?
}

I just translated this to PW from a Perl module I had, so please feel free to correct my PW syntax since I'm new to this.

Thanks,

thomas

  • Like 3

Share this post


Link to post
Share on other sites

@thomas Thanks for this, I will take a look and maybe change to this code as my implementation does not have the weighting you've got here. Cheers, -Alan

Share this post


Link to post
Share on other sites

FWIW, I recently did something similar, but on various fields from $page->siblings with php's similar_text() function (and stopwords).

  • Like 1

Share this post


Link to post
Share on other sites

Hello,

I am going to resurrect this old post to share my "related pages" approach. It uses the described pages-as-tags and then looks for pages with the same tags. The more tags are shared, the more "related" the other page is, thus getting it further up on the list.

foreach($page->tags as $tags) {
$tag = $sanitizer->selectorValue($tags->title);
$related_pages = $pages->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); ?>
<a href="<?=$rp->url;?>"><?=$rp->title;?><br><?
}

I just translated this to PW from a Perl module I had, so please feel free to correct my PW syntax since I'm new to this.

Thanks,

thomas

Thomas, I just today implemented something similar and remembered the logic from your post. Simple and great solution. I made few modifications - most notably I save the related pages into page field also. I also run this code only once per page, since this is part of the import script. Here is how I modified your code:

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);
 $page->related_articles->add($rp);
}
  • Like 4

Share this post


Link to post
Share on other sites

Hi apeisa,

that's great. I also played around with this and return a PageArray now. I also tried to use the "weight" as a temporary field in my PageArray so I can sort by weight (like $related->find("sort=weight,sort=-created,limit=3")) but I couldn't get the temporary field to work.

$rp = new PageArray();
foreach($related_id as $key => $val) if($tmp++ < $limit) {
 $rp->add($pages->get($key));
}

Does anyone know a way to add a temporary field to each page I add to the PageArray $rp, which I can use to sort after I return $rp?

Thanks,

thomas

Share this post


Link to post
Share on other sites

Those should be automatic, like this

$page->temp = "hello";

echo $page->temp;

Share this post


Link to post
Share on other sites

Since this thread is related :), I'm also posting this here. I wrote a little helper module to find related pages with score and sorting by score AND modified.

Module code can be found here: https://gist.github.com/3558974

$pages->findRelated( Page $page, PageArray $tags, string $field [, string $tmpl, int $limit] );

It add a $pages->findRelated() method. You can do something like this:

$found = $pages->findRelated($page, $page->tags, 'tags', 'product|product2', 100);
if($found) {
 foreach( $found->slice(0,5) as $rel ) {
   echo "<p><a href='$rel->url'>$rel->title</a> ($rel->score)</p>";
 }
} else {
 echo "<p>No related Products found</p>";
}
  • Like 6

Share this post


Link to post
Share on other sites

Soma, this looks cool, but I'm not sure I fully understand exactly what it does. I've been looking at the code and the function arguments for a bit here, as well as the other thread, and a little confused?

Share this post


Link to post
Share on other sites

Soma, this looks cool, but I'm not sure I fully understand exactly what it does. I've been looking at the code and the function arguments for a bit here, as well as the other thread, and a little confused?

What don't you understand? I thought you understand code more than words? ;)

I can't explain more without repeating what I already wrote.

It does search for pages that have the same tags selected, counts the tags matching and adds that to the score property and sorts by score AND modified, so the most recent are first.

$pages->findRelated( Page $page, PageArray $tags, string $field [, string $tmpl, int $limit] );

$page = current page or another one (to exlude it from the search)

$tags = a PageArray of tags

$field = the Page field which holds the tags, to know which field to search

optional:

$tmpl = the template of the pages to search in. Multiple templates like "t1|t2|t3"

$limit = how many to search

It returns a PageArray which can be used further, if none found it returns null.

  • Like 1

Share this post


Link to post
Share on other sites

$pages->findRelated( Page $page, PageArray $tags, string $field [, string $tmpl, int $limit] );

$page = current page or another one (to exlude it from the search)

$tags = a PageArray of tags

$field = the Page field which holds the pages to search

optional:

$tmpl = the template of the pages to search in. Multiple templates like "t1|t2|t3"

$limit = how many to search

It returns a PageArray which can be used further, if none found it returns null.

Thanks Soma, this clarified it for me.

Share this post


Link to post
Share on other sites

Hi Soma,

I just included your module in a page i'm working on, which already has over 400 videos complete with tags imported from the old site. It works great! I only changed the SQL query to "ORDER BY score DESC, modified, ASC" since that makes more sense in my case.

Thanks for your work!

- thomas

Share this post


Link to post
Share on other sites

Glad it works out for you thomas! Feel free to adapt it to your needs, it's not an official module just a little helper.

Share this post


Link to post
Share on other sites

Great! Exactly what I was looking for to display related content based on common tags.

If I find the time – and if my limited PHP knowledge will be sufficient :huh: – I’m going to extend this to be able to find related content based on more than one field. This would also be a great addition to display search results based on their relevance. If there is not yet a solution which does so …

Share this post


Link to post
Share on other sites

Here's a bit of code that you might find useful. It's something that I referred to earlier in this thread.

Say you have a group of pages that represent businesses - like entries in a business directory. Put something like this at the top of your template for each business.

<?php
$siblings = $page->siblings();
foreach($siblings as &$sibling){
$pagetext = strtolower($page->title.' '.$page->city.' '.$page->postcode);
$siblingtext = strtolower($sibling->title.' '.$sibling->city.' '.$sibling->postcode);
$stopwords = array('limited','shop','emporium');
$pagetext = str_replace($stopwords,'',$pagetext);
$siblingtext = str_replace($stopwords,'',$siblingtext);
similar_text($pagetext, $siblingtext, $sim);
$sibling->similarity = $sim;
}
$siblings->sort('-similarity');
?>

$stopwords are words you want to be ignored in the comparison (in my real-world use they are business-specific terms that a great many businesses have in their names).

Then to display a list of similar entries...

<?php
$score = 40;
if($siblings->eq(1)->similarity >= $score){
echo '<h3>Similar Entries</h3>';
echo '<ul>';
for($i = 1;$i <= 10;$i++){
 if($siblings->eq($i)->similarity < $score) continue;
 echo "<li><a href='{$siblings->eq($i)->url}' title='{$siblings->eq($i)->title}, {$siblings->eq($i)->address}, {$siblings->eq($i)->city} {$siblings->eq($i)->postcode}'>{$siblings->eq($i)->title}</a>";
 if($user->isSuperuser()) echo ' '.round($siblings->eq($i)->similarity, 2);
 echo "</li>";
}
echo '</ul>';
}
?>

Adjust $score to get satisfactory results. (And the bonus prize is that logged-in super users get to see the score in the page output.)

  • Like 2

Share this post


Link to post
Share on other sites

Hi guys,

Sorry to drag up an old thread but this is probably the best place for it. I have implemented Thomas' code but I need to put a limit on the number of pages returned as I only have space for 4 in my markup. I have tried putting the limit selector in various places but I always get an error.

Thanks

Anthony

Hello,
I am going to resurrect this old post to share my "related pages" approach. It uses the described pages-as-tags and then looks for pages with the same tags. The more tags are shared, the more "related" the other page is, thus getting it further up on the list.
 

foreach($page->tags as $tags) {
$tag = $sanitizer->selectorValue($tags->title);
$related_pages = $pages->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); ?>
<a href="<?=$rp->url;?>"><?=$rp->title;?><br><?
}
I just translated this to PW from a Perl module I had, so please feel free to correct my PW syntax since I'm new to this.
Thanks,
thomas

Share this post


Link to post
Share on other sites

Anthony, have you tried

$related_pages = $pages->find("tags.title=$tag,limit=4");

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.

×
×
  • Create New...