Query a structure field which queries another structure field

Hi everyone - I’m trying to add some features to a housing developer website I’ve been working on, and have what is probably quite a basic problem I was hoping for some help with as I continue to (slowly) improve my Kirby skills.

Currently I have a ‘development.yml’ blueprint and in it am defininf ‘house types’ like this:


      housetypes:
        label: House types
        type: structure
        fields:
          name:
            label: Name
            type: text
          bedrooms_no:
            label: Number of bedrooms
            type: number  

In the same blueprint I am also defining plots, each which has a housetype attached to it, by querying the above structured fields:


      plots:
        label: Plots & Availability
        type: structure
        fields:
          plotNumber:
            label: Plot Number
            type: number
            width: 1/4
          plot_housetype:
            label: House type
            type: select
            width: 3/4
            options: 
              type: query
              query: page.housetypes.toStructure
              text: "{{ item.name }}"
              value: "{{ item.name }}"
          price:
            label: Price
            type: text
          availability:
            label: Available?
            type: toggles
            options:
              - available
              - sold
              - coming soon

I can display the current housetypes for a development by looping through the housetypes as follows:

<?php
    $housetypes = $page->housetypes()->toStructure();
    foreach($housetypes as $ht): ?>
<div class="housetype-card">
  <?php if($htImage = $ht->featuredimage()->toFile()): ?>
  <img loading="lazy" alt="<?= $htImage->alt() ?>" src="<?= $htImage->url() ?>" height="<?= $htImage->height() ?>"
    width="<?= $htImage->width() ?>" class="background-cover ">
  <?php endif ?>
  <div class="headline-bar rbl-bg-olive d-flex flex-column py-3 px-4">
    <span class="plot-heading"><?= $ht->name() ?></span>
    <span class="rbl-font-serif m2"><?= $ht->area() ?>m²</span>
  </div>
</div>
<?php endforeach ?>

That’s fine and that’s the easy part. But what I now want to do is display a badge that shows availability of the housetypes (based on the ‘avaibality’ toggles ) according to the plots.
So for example, if the housetype in the foorloop card is called ‘tudor’ then we need to check all the plots for any with ‘tudor’ as the housetype value, then check if any are available. Then I need to do a count:

‘3 available’ (and if none available say not available)

My guess is I need to loop through the plots structured fields and query the housetype name.
so this is incredibly wrong, but allow me to my best to show you what i mean: (please be kind, I am still learning!)


<?php
    $housetypes = $page->housetypes()->toStructure();
    foreach($housetypes as $ht): ?>
<div class="housetype-card">

  <span class="badge">
  
   <!-- find all plots with this housetype and availability toggle set to 'available' -->
  <? $htplot = $page->plots()->toStructure()->findBy('housetype', $ht) & 'availability' == 'available'?>
  
    <?php if($htplot->count() > 0  )?>
    <?= $htplot->count() ?> available
    <?php else: ?>
    Not available
    <?php endif ?>
  
  <? endforeach ?>
  
  </span>

</div>
<?php endforeach ?>



Thanks all for bearing with me!

You are looking for the filterBy method. See the guide about “Filtering collections”, especially the part about filtering by more than one field (1. plot_housetype, 2. availability).

The findBy method you used above always just finds 1 item (the first one that matches your criteria) or null, so findBy doesn’t probably return a collection you would want to count.

Inside of your loop that would be:


<?php
$htplot = $page
    ->plots()
    ->toStructure()
    ->filterBy('plot_housetype', $ht)
    ->filterBy('availability', 'available');
?>
<?php if($htplot->count() > 0  )?>
  <?= $htplot->count() ?> available
<?php else: ?>
  Not available
<?php endif ?>

You could also do part of this work outside of the loop to repeat less of the work:


<?php
$housetypes = $page->housetypes()->toStructure();  

// filter for all available plots 
$availablePlots = $page
    ->plots()
    ->toStructure()
    ->filterBy('availability', 'available');
?>

<?php foreach($housetypes as $ht): ?>
  <div class="housetype-card">
    <span class="badge">
      <?php $htplot = $availablePlots->filterBy('plot_housetype', $ht); ?>

      <?php if($htplot->count() > 0): ?>
        <?= $htplot->count() ?> available
      <?php else: ?>
        Not available
      <?php endif ?>
    </span>
  </div>
<?php endforeach ?>
1 Like

Thank you so much @rasteiner - I’m going to give this a go this evening but it makes a lot more sense. Thanks for the link too :slight_smile: