How to use blueprint select queries for 2 different things?

I want to do something simple but I can’t figure out if it’s possible or not, maybe you can help me to think.

On my portfolio I have a hero image, and for the moment the first image of the page is showing up as hero image.

I want to be able to select what image is the hero one in the panel with a select field. This part is easy with :

heroimage:
  label: Image d'en-tête
  type: select
  options: query
  query: 
  fetch: images
  value: '{{url}}'
  text: '{{filename}}' 

With this code, I can retrieve the URL of the file and display it in a <img src""> tag.

The hard part is that I don’t want to show the hero image again in the page image if I selected a hero image, so I’ve thought to use the not() filter in my foreach but I cant use the url string as an argument.

Is there a way to retrieve the entire object with the select query, si I can filter my variable with all the kirby filters, like heroimage()->url() and just heroimage() as an object for the not() filter ?

Is there another way to achieve what I want to do ? Maybe add a second value ? Maybe there is a syntax for retrieving the full object ?

Thanks for your help.

I would update the blueprint to store the filename instead of the URL:

heroimage:
  label: Image d'en-tête
  type: select
  options: query
  query: 
    fetch: images
    value: '{{filename}}'
    text: '{{filename}}'

Then you can get the image object with $page->heroimage()->toFile() (http://getkirby.com/docs/cheatsheet/field-methods/toFile).

In your image tag you get <img src="<?= $page->herimage()->toFile()->url() ?>" and $page->images()->not($page->heroimage()->toFile()) for your filter.

Great, the toFile() function was the missing link ! Thak you very much, it’s perfect. Exactly what I wanted to do. I will test it later.

Unfortunatelly, the $page->images()->not($page->heroimage()->toFile()) in filter throw me this error :

Warning: Illegal offset type in unset

Same for $page->images()->not($page->heroimage())

Any idea @FabianSperrle ?

A wild guess would be that heroimage() returns an empty string because the field is empty in your page. Then $page->heroimage()->toFile() is null which is not a valid offset for the call to unset in collection::not(): https://github.com/getkirby/toolkit/blob/master/lib/collection.php#L166

Can you check whether the field is empty before running toFile() on the value?

OK, here’s the missing bit : $page->images()->not($page->heroimage()->toFile()->filename())

items are excluded by filename as I thought, but you have to transform it first in object with toFile() THEN retrieve the filename with the chaining of ->filename()

Thank you for your kind help.

I think inconsistencies like that between page- and file-collection methods should not exist. There is no reason why you should be able to pass a page object to $pages->not(), but not a file to $files->not() @bastianallgeier.

Yep, that’s what bug me a little with this issue (also, i’m a total dev n00b, i’m a designer ^^)

The weird and not so obvious thing is that $page->heroimage() already print the filename so you thought you can use it as a filter in not(), but you can’t, you have to transform it to an object first and then retrieve the filename from it with $page->images()->not($page->heroimage()->toFile()->filename())

That’s because $page->heroimage() actually returns an object. When used in templates, the toString() method is called and you get your normal output that you would expect. To use it in the filter, you have to access the field value as a string (images()->not($page->heroimage()->value())) or cast the object to string: $page->images()->not((string) $page->heroimage()).

Or the kirby way:

$page->images()->not($page->heroimage()->toString())

Thanks @FabianSperrle I understand better.

@texnixe OK I’m going to use thai syntax.

thanks.