Jump to content

Selector and Page reference field


formmailer
 Share

Recommended Posts

Hi,

I need a selector to find pages that are using the template "poi" and that are having a page reference to a page with the title "Zoo".

The page reference field is called poi_type.

How would I do this?

I tried this:

$poi = $pages->find(template=poi, poi_type.title='Zoo'); 

But it doesnt work because there is no field poi_type.title.

/Jasper

Link to comment
Share on other sites

Now it becomes more complicated: I need to include page references to the selector, for example: Zoo, Theme park and Museum.

The first line becomes:

$pr = $pages->get("title=Zoo|Theme park|Museum");

But the second line only finds the pages in the first category (or last, I don't remember).

I assume that I need to cycle through $pr and include the results into the existing Array ($poi). Is that correct?

/Jasper

Link to comment
Share on other sites

Works with many to many too.

$prs = $pages->find("title=Zoo|Theme park|Museum"); // maybe also use the name or id
$poi = $pages->find("template=poi, poi_type=$prs");

EDIT: corrected code. yours doesn't work because "get" will return only 1 page and not page array.

  • Like 6
Link to comment
Share on other sites

Thanks Soma!

I often forget what returns a single object or an array of objects. I really need to sit down some time and learn this basic stuff for real. It will save me quite some time searching and asking while building new things. :)

Yes, I will probably use the page ID instead of the title, that seems to be a bit safer.

/Jasper

Link to comment
Share on other sites

  • 3 months later...

Hi, I'm new here, I'll start by posting in an existing thread ;-)

I'm trying to do something similar than the OP, but I can't get it to work :

Basically,

- I have pages with template "one-category", where each page represent one category

- I have pages with template "one-article", which are used for the actual contents.

- one of the fields of "one-article" is "article_categories", it is of type "Page", more specifically "Multiple pages (PageArray)". It is used to reference a list of pages of type "one-category" (which means it is used for assigning categories to each article).

Now, I want to select, for each existing category pages, the list of the "one-article" pages which are referencing the category.

For troubleshooting, I also try to "just" select all the "one-article" pages which are referencing one single category page.

here is the code :

$the_articles = $pages->find("template=one-article"); // select all existing real pages
$the_cat = $pages->get("template=one-category, title='cat1'"); // select one category page
$the_list = $the_articles->find("article_categories=$the_cat"); // select real pages referencing the desired category page

as a result,

- this is working if I have only 1 category referenced in the articles : $the_list->count() returns '1' for the relevant article, and I can use the returned objet

- but it (seems to) fail as soon as I add a second category to this article : $the_list->count() now returns '0', while I would expect it to still return '1'

any idea ?

  • Like 1
Link to comment
Share on other sites

Welcome to the forums er314. I think what you want may be this:

$the_cat = $pages->get("template=one-category, title=cat1"); 
$the_list = $pages->find("template=one-article, article_categories=$the_cat"); 

It sounds like you might be performing this from your one-category template, so in that case you could just do this:

$the_list = $pages->find("template=one-article, article_categories=$page");

In addition to the above, you might want to specify a "sort" in your selector, like "sort=date" (if you have a field called that) or "sort=title" or something like that. Though if you change your call to something like this, then it would automatically sort by whatever is defined with the /articles/ page:

$the_list = $pages->get("/articles/")->children("article_categories=$page"); 
Link to comment
Share on other sites

er31,

Where do you call this code, in your categories template?

I'm not sure but i guess the problem lies in the fact that $pages->get returns a Page and not a PageArray. You should alter the $the_cat part is guess, but i could be wrong :)

Link to comment
Share on other sites

Thanks,

Currently, for testing (and for understanding/learning !) purpose, I'm doing the request outside of the category template,

So yes Ryan your 1st solution, the one with 2 selects, is working, thanks a lot !

For the sake of understanding/learning,

as I will have to perform several requests/selections of this type in the same block of code, my aim was to

- first, perform only once the supposedly "heaviest" request (the one which queries all pages)

- then, perform the subsequent requests not on all pages, but on the "one-article" subset of pages

Hence, my initial code, which added an intermediate step (3 selections instead of 2, with the heaviest first)

-> Ryan, do you know exactly what was wrong in my initial code ?

Can it be fixed, while preserving this 3 steps behaviour ?

Or should I just forget about that, given that this kind of optimization is probably negligible ?

(my aim is to display, in the category tree view, the number of "one-article" pages for earch category ; well, a bit like the "Pages" view in PW admin interface...)

Link to comment
Share on other sites

You think could use something like this:

$categories = $pages->find("template=one-category");

foreach ($categories as $cat) echo '<p>' . $cat->title . ' (' . $pages->count("template=one-article, article_categories=$cat") . ')</p>';

or, if you use it in your category template:

echo '<p>Category ' . $page->title . ' has ' . $pages->count("template=one-article, article_categories=$page") . ' articles!</p>';

Edit:

Or should I just forget about that, given that this kind of optimization is probably negligible ?

Processwire is optimized for such requests, so there shouldn't be any serious penalties for using several queries in a loop.

Link to comment
Share on other sites

$the_list = $the_articles->find("article_categories=$the_cat"); // select real pages referencing the desired category page
-> Ryan, do you know exactly what was wrong in my initial code ?

There's nothing wrong with your code, but just a difference of context here. The issue is that a few of the in-memory selectors sometimes aren't as smart as the DB-driven ones. Your code quoted above is an in-memory find() provided by the WireArray class. It is used throughout the system, and it performs literal string comparisons. Whereas the DB-driven one is sending out queries to be answered by MySQL, often with a lot more context than string comparison. Most of the time, the two should perform the same, so this is one instance where they don't. It may be something I can account for. I hadn't noticed this before because it's somewhat rare to do this type of in-memory find() where you are finding/filtering pages based on pages within pages. In-memory finds and filters aren't ideal because it usually means that more pages have been loaded into memory than were actually needed. So it's preferable to avoid situations that result in post-filtering or post-finding, when possible. In your case, it sounds like you are going to use all the pages, but just using find() to group them differently. If you want to stick with that route, I would do this:

$the_list = new PageArray();
foreach($the_articles as $a) {
 if($a->article_categories->has($the_cat)) $the_list->add($a); 
}

The above also reveals the technical reason why the in memory find failed. The string value of $article_categories and $the_cat won't match unless $article_categories only has 1 category and it is $the_cat. That's why we had to use has() to compare them, which is something that WireArray::find has no contextual awareness of. I'm going to see if there is some way to make them work the same. Thanks for bringing it up.

Link to comment
Share on other sites

  • 4 months later...

Works with many to many too.

$prs = $pages->find("title=Zoo|Theme park|Museum"); // maybe also use the name or id
$poi = $pages->find("template=poi, poi_type=$prs");

EDIT: corrected code. yours doesn't work because "get" will return only 1 page and not page array.

Just wanna thank Soma for this. Been searching for selector for page references for an hour. This solved my problem. :)

  • Like 1
Link to comment
Share on other sites

  • 6 years later...

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