Content relation between Kirby pages

I have this content structure:

1-home
2-products
  1-category-one
    1-product-one
    2-product-two
    3-product-three
  2-category-two
    1-product-four
    2-product-five

Any product has an image, title & text fields.

In the home I need to show image & title of 2 products eg. (product-two, product-four), any ideas?

try building a collection by filtering, sorting, … example

$special = page('products')->children()->visible()->filterBy('tags', ',', 'special')->sortBy('date','desc')->limit(2);

To fetch a single product, you can also pass the complete path to the page helper:

$product1 = page('products/category-one/product-one');
$product1 = page('products/category-two/product-five');

It all depends what you want to achieve. You can also add a checkbox field to each page, e.g. “showOnHomepage?”, and then filter your products by this checkbox.

I succeeded (see the code below), the only bad thing that Panel structure field doesn’t show Title inside entry: field of selected product, it is possible?


Here’s code:

blueprint:

products:
  label: Products
  type: structure
  entry: {{product}} # show the {{uri}} value in panel :(
  modalsize: large
  fields:
    product:
      label: Product
      type: quickselect # quickselect or select fields works well
      options: query
      query:
        fetch: pages
        template: product # search pages only with `product` template
        value: '{{uri}}'
        text: '{{title}}'
      required: true

template:

<?php
  $products = [];
  foreach ( $page->products()->toStructure() as $related ) {
    $products[] = page( $related->product() );
  }
?>
<?php if ( count( $products ) ) : ?>
  <section>
    <h2>Featured Products</h2>
    <?php if ( count($products) or $products->count() ) : ?>
      <ul>
        <?php foreach ( $products as $product ) : ?>
          <a href="<?= $product->url() ?>" rel="bookmark"><?= $product->title()->html() ?></a>
        <?php endforeach; ?>
      </ul>
    <?php endif; ?>
  </section>
<?php endif; ?>

The value that is shown depends on the value that is saved in the content file. You might want to look into using the snippet field instead of the native structure field. It gives you more freedom as regards what the entry can display.

If I switch to another language I’m also getting: Whoops \ Exception \ ErrorException (E_ERROR) "Call to a member function url() on boolean". This happening because of:

<a href="<?= $product->url() ?>" rel="bookmark"><?= $product->title()->html() ?></a>

Looks like you are using URL-Keys for the non-default languages?

Yes, URL-keys are in all non-default languages

Looks like you can’t get the page via its translated URI… looking into how to solve this.

I’ve I tried to var_dump($product) and it returns me an Object :ok_hand: on default language and bool(false) bool(false) bool(false) on non-default language :confused:.

That’s what I meant…

But apart from this issue, I wonder why you use two if statements?

You are right it can be done with only first statement: if ( count( $products ) ) :.
Anyway I can’t getting work on non-default languages … :frowning:

One thing that seems to work is this:

foreach ( $page->products()->toStructure() as $related ) {
    $p = $site->index()->findByURI($related->product());
  }
dump($p);

You don’t have to create the $products array first, btw…

2 Likes

You are right, thank you it works:

<?php if ( $page->products() ) : ?>
  <section>
    <h2>Featured Products</h2>
    <ul>
      <?php
        foreach ( $page->products()->toStructure() as $related ) :
        $product = $site->index()->findByURI( $related->product() );
      ?>
        <li>
          <a href="<?= $product->url() ?>" rel="bookmark"><?= $product->title()->html() ?></a>
        </li>
      <?php endforeach; ?>
    </ul>
  </section>
<?php endif; ?>
1 Like