Nico Knoll

Module want: Related pages

72 posts in this topic

Hi,

I would like to have a module which shows me related pages to the current (or an PageArray).

Greets,

Nico

Share this post


Link to post
Share on other sites

This can already be done easily with a field.

Simply create a new field with type "Page".

Under the Details tab make sure "Multiple Pages" is selected.Under the Input tab, change "Parent of selectable page(s)" to be your parent blog page (ie. the page that all your articles come under). Finally, change "Input field type" to be asmSelect to allow you to mre easily select multiple blog entries.

That's the hard part done. Then in a template you can iterate through that field and display links to related pages :)

EDIT: I guess that technically you would want the link to work both ways though so it you link one page to another then if you're viewing the other page it would link back, but it wouldn't be too hard to do - simply do an additional search on all pages with the "relatedpages" field and return results with a link to the current blog entry - that way you don't have to worry about adding links between multiple pages.

Share this post


Link to post
Share on other sites

There is a video that showing the kind of approach Pete describes. http://processwire.com/videos/page-fieldtype/

But i'm guessing you want something a little more 'automated'. A module/class that would allow you define some parameters like which pages and fields you want to search for possible relations, give fields a weight, excludes stopwords, and then searches and calculates a ranking/resultset based on the things you define.

You would call this module/class in your template, possibly using MarkupCache to avoid a performance hit.

Could you elaborate on what functionality you would like to see in your "Related pages" module?

Share this post


Link to post
Share on other sites

At the end I want to use something like:

$page->relatedPages as $relatedPage {
echo $relatedPage->title; // $relatedPage should be a PageArray
}

It should work completely automatically. And I want to have an option page where I can say what is the most important point in which they should be related with. And maybe the second important and the third or so.

I guess it would work like a specified search which caches like 5 related page in each page. And if I create a new page it looks for related pages and saves them in the "relatedPages" field (so it probably should be a Fieldtype). So the module wouldn't increase the front-end's loading time.

Share this post


Link to post
Share on other sites

Well I guess the question here is what determines how they are related? Similar words in the title such as "apple"? It might be better to go with a "tags" field for that approach (basically a text field with comma separated values and just do searches on the tags field for other articles containing the same tags.

If you could give us a better idea of how you would see it being automated ie. what the module is looking for in order to determine how a page is related, then I'm sure we can come up with other suggestions.

1 person likes this

Share this post


Link to post
Share on other sites

Yep. That is exactly what I tried to ask in first reply. Automatic relation, but based on what? Comparing words on body content? Similar titles? Same tags used?

Share this post


Link to post
Share on other sites

I think my template would have a "category" and a "tags" field. So first it should look for the same tags. (And maybe in the second step for the same category)

Share this post


Link to post
Share on other sites

In which case you could set up your categories as pages under a categories page - these would then return any entries in that category. This would be set up in the way I first mentioned so in your article template you create a field with type "Pages" and you can link an article to multiple categories.

Then you can grab all articles from that category reasonably easily to display on the category page (we'll get back to the automatically related articles in a bit) using something like this where $page->name is the category page you're viewing:

$articles = $pages->find("category=$page->name, limit=50");

where 50 is the limit for the number of articles to return.

In terms of tagging, you simply get all tags for the current page (we're assuming "tags" is a text field with just comma-separated tag names) and use similar code to the above to return all articles with the same tags:

$related_articles = array();
$tags = explode(',', $page->tags);
foreach ($tags as $tag) {
   $tag = trim($tag);
   $articles = $pages->find("tags*=$tag");
   foreach ($articles as $article) {
       if (!isset($related_articles[$article->id])) {
           $related_articles[$article->id] = $article; // Not sure if this saves any overhead - just makes sure we're not overwriting duplicate array entries if 2 articles have the same tags
       }
   }
}

Then you can iterate through your $related_articles and print the list.

I'm not sure if the search is case-sensitive, but I would suggest inputting all your tags in lowercase just to be on the safe side.

Another interesting thing you can do is count the number of times a tag appears and create a tag cloud for all your articles (this would require getting all tags for all articles, but it's just a variation on the above).

Share this post


Link to post
Share on other sites

$articles = $pages->find("category=$page->name, limit=50");

You can just use:

$articles = $pages->find("category=$page, limit=50");

The $page is the current category page, which serves also as the catergory page to select in the articles. So category is a page reference field on the article pages.

Also you could use template with urlSegments enables to setup a page "categories" that lists pages from a category, you can use like: /categories/categoryname/

Then use something like this:

$cat = $sanitizer->pageName($input->urlSegment(1));
$articles = $pages->find("category=$cat, limit=10");

Edit: Sorry corrected some in the code, its $input->urlsSegment() not $page->urlSegment(). And $sanitizer-> not $page->sanitizer

Share this post


Link to post
Share on other sites

You can just use:

$articles = $pages->find("category=$page, limit=50");

Very good point :)

Share this post


Link to post
Share on other sites

I'm using this approach in order that I may tag pages that share a common theme.

I've not got to writing any code yet, just setting up fields/templates.

I have a hidden parent page called 'Tagging' and under it a page per tag.

But when I am in the editor and adding a new tag (page) or two, the resultant pages are not set to 'Hidden'.

I've tried to make them hidden by changing my template Access settings but that was only an educated guess — is there a way to make pages create pre-set to hidden, or, as the pages are under a hidden parent am I safe to not care that they are not hidden?

Any comments gratefully received :)

Edit: Larger question may be -- am I wrong to have the parent of the tags as a hidden page in my hidden '_Tools' section rather than calling it, say, 'tags' and having it visible immediately under Home?

Share this post


Link to post
Share on other sites

If you assign to those pages a template without file they will always be hidden and you don't have to worry about it. And if you don't want them to be viewable, I'm assuming you didn't setup a template file.

As for the larger question: I wouldn't say you're wrong, but you could have all the tags listed on your tagging page, and on each tag page, all the articles tagged with it. It's not much work, and maybe nicer than having them hidden.

Share this post


Link to post
Share on other sites
If you assign to those pages a template without file they will always be hidden and you don't have to worry about it

Excellent.

And if you don't want them to be viewable, I'm assuming you didn't setup a template file.

Correct.

As for the larger question: I wouldn't say you're wrong, but you could have all the tags listed on your tagging page, and on each tag page, all the articles tagged with it. It's not much work, and maybe nicer than having them hidden.

I don't understand that, but I'm experimenting with tagging today so I will see if I can understand it when I've done a little more learning. Thanks diogo for the help.

Share this post


Link to post
Share on other sites
I don't understand that

sorry for the messy sentence :) I just meant having them visible as in any blog

Share this post


Link to post
Share on other sites
sorry for the messy sentence :) I just meant having them visible as in any blog

Ah I understand, thanks diogo and NO need to apologise! :D

Share this post


Link to post
Share on other sites

Alan, if your tools page is hidden, you don't need to set all children of it to hidden. Usually we set a page hidden, to not show up in navigations. So it's basicly enough to have the parent set to hidden.

Share this post


Link to post
Share on other sites

PHP is cleverer than I am I think :(

In an attempt to work out what I am doing wrong I have moved my parent tag page to directly under Home and renamed it to simply 'tags'.

Using this code I am getting:

Error Exception: Operator '*=' is not implemented ... etc

So I edited it like so to try and see if I could help myself:

$related_articles = array();
$tags = explode(',', $page->tags);
foreach ($tags as $tag) {
$tag = trim($tag);
echo $tag;
//	$articles = $pages->find("tags*=$tag");
//	foreach ($articles as $article) {
//		if (!isset($related_articles[$article->id])) {
//			$related_articles[$article->id] = $article; // Not sure if this saves any overhead - just makes sure we're not overwriting duplicate array entries if 2 articles have the same tags
//		}
//	}
}

...the commenting out just to stop the error and the addition of echo $tag; to see if that told me anything. Using the edited code I am getting no errors and the IDs of the pages that any given page is tagged with are output, which is good as far as it goes.

I've tried hard to solve the error, searched and read but my Achilles PHP-simpleton-heel has thwarted me.

Does anyone see why I may be getting this error, please and thanks?

Share this post


Link to post
Share on other sites

The reason for this is simple :)

$pages->find("tags*=$tag");

doesn't work because "tags" field is most likely not fulltext field like "title", thus not working with *= . Try setting the field to "autojoin". Not sure though... gotta continue work. But hope this helps. :)

Share this post


Link to post
Share on other sites

Thanks Soma :)

I checked and the only differences I can see between the 'tags' field and the 'title' field is that 'title' had Autojoin and Global ticked.

I tried ticking these (in case one/both were the definition of a fulltext field) but the error is still present.

I tried following the advice here:

The *= and ~= rely upon MySQL fulltext indexes, which only index words of at least a certain length (configurable, but typically 4 characters). They also don't index common English words called stopwords. So while it's preferable to use *= and ~= for their speed, if you aren't getting the results you need, you should consider using %= instead (if you can handle the speed hit).

and changed the selector from *= to %= but the error is still present.

Any other ideas greatly appreciated :)

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

Global you shouldn't set, because it will add it to all templates I think. Just autojoin should do the trick.

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.