Show just a portion of a structured field on a template page using a controller. Basically a dynamic detail view when user clicks on the item

Functionality Needed: When user clicks on the item image it should filter and only show the following fields from that item (image, itemnumber, price and fulldescription).

What I’ve tried:

Controller (site/controllers/sidemenuproducts.php)

<?php

return function ($page) {
    $filterBy = get('filter');
    $unfiltered = $page->items()->toStructure();
    $items = $unfiltered
    ->when($filterBy, function($filterBy) {
        return $this->filterBy('item', $filterBy);
    });

    $filters = $unfiltered->pluck('item', null, true);

    return [
        'filterBy' => $filterBy,
        'unfiltered' => $unfiltered,
        'items' => $items,
        'filters' => $filters
    ];
};

Template Section (site/templates/sidemenuproducts.php)

<table id="items_listing">
    <tbody>
      <?php foreach ($page->items()->toStructure() as $item): ?>
      <tr>
        <td>
      <a href="?filter=<?= $item->itemnumber() ?>"><?= $item->image()->tofile() ?></a>
      <br>
      <?= $item->itemnumber() ?>
    </td>
        <td>
      <?= $item->shortdescription() ?>
        </td>
    <td>
      <?= $item->price() ?>
    </td>
      </tr>
     <?php endforeach ?>
    </tbody>
   </table>

^ I’m assuming it is not working because I need an If/Else statement in my template file, not sure what that code should be.

sidemenuproducts.yml

title: Sidemenu Page

tabs:
  content:
    icon: list-bullet
    label: Items
    columns:
      main:
        width: 1/1
        sections:
          fields:
            type: fields
            fields:
              alert:
                label: Alert
                type: textarea
              items:
                label: Items
                type: structure
                fields:
                  image:
                    label: Image
                    type: files
                    max:1
                  imagedescription:
                    label: Image Description
                    type: text
                  itemnumber:
                    label: Item Number
                    type: text
                  newitemdate:
                    label: New Item Date
                    type: text
                  reducedprice:
                    label: Reduced Price
                    type: number
                  price:
                    label: Price
                    type: number
                  shortdescription:
                    label: Short Description
                    type: tinymce
                  fulldescription:
                    label: Full Description
                    type: tinymce

  seotab: seo

Ok,

  1. When you define your variables in a controller, don’t redefine in your template, so in your template loop through $unfiltered, not through $page->items()->toStructure().

  2. In the controller, you are filtering by a field item, but such a field is not present in your structure field, so you need to filter by something that is unique in that structure field, which is probably the number, also, you only want a single item, so findBy() instead of filter.

// ...
$filter       = get('filter')
$items        = $page->items()->toStructure();
$selectedItem = $filter ? $items->findBy('itemnumber', $filter) : null;


 return [
        'filter'       => $filter,
        'items'        => $items,
        'selectedItem' => $selectedItem
    ];

Then in your template

<?php if ($filter && $selectedItem): ?>
<!-- markup and fieldsof selected item -->
<?php else: ?>
 <?php foreach ($items as $item): ?>
    <!-- show the list in the table  here -->
 <?php endforeach ?>
<?php endif ?>
1 Like

Okay. I tried that.

This is in the controller:

<?php

return function ($page) {
    $filter       = get('filter')
    $items        = $page->items()->toStructure();
    $selectedItem = $filter ? $items->findBy('itemnumber', $filter) : null;


 return [
        'filter'       => $filter,
        'items'        => $items,
        'selectedItem' => $selectedItem
    ];
};

Getting the following error:

syntax error, unexpected variable “$items”

Where is it undefined, please show the stacktrace!

Semicolon missing after filter definition…

$filter       = get('filter');
1 Like

Filtering is now working!

I’m getting returned data from all items though…

Here is my template code

<?php if ($filter && $selectedItem): ?>
				<!-- markup and fieldsof selected item -->
				<?php foreach ($items as $item): ?>
					<?= $item->itemnumber() ?>
				<?php endforeach ?>
				<?php else: ?>
				<?php foreach ($items as $item): ?>
				<!-- show the list in the table  here -->
					<table id="items_listing">
						<tbody>
								<tr>
									<td>
										<a href="?filter=<?= $item->itemnumber() ?>"><?= $item->image()->tofile() ?></a>
										<br>
										<?= $item->itemnumber() ?>
									</td>
									<td>
										<?= $item->shortdescription() ?>
									</td>
									<td>
										<?= $item->price() ?>
									</td>
								</tr>
						</tbody>
					</table>
				<?php endforeach ?>
				<?php endif ?>

Well, as I wrote above, here you show the single item, don’t loop through $item when the filter is set, don’t know why you are looping through all items twice?

so

<?= $selectedItem->shortdescription() ?>
1 Like

That makes total sense (I didn’t pass the variable back into the template). Cloudy brain kinda of day…

This is the solution. Thanks!!

@texnixe

Is there a way to just search only the filtered item pages and show as results on the Kirby search?