Fetch query from parent page

Hey, i need to get the result of a structure as a select from a children page.
I have the main page with this:

categorias:
label: Categorias
type: structure
entry: {{categoria}}
fields:
categoria:
label: Nome da Categoria
type: text

And the page inside it i need the option to choose from all the entries added in “categoria” on a select.
Is it possible?
Thanks in advance

Yes, you can do that via a custom form field : http://getkirby.com/docs/panel/custom-form-fields

You can adapt this example by just replacing the value for $categories with the structure fields:

<?php

class CategoryField extends BaseField {

  public function __construct() {
    $this->type    = 'category';
    $this->icon    = 'chevron-down';
    $this->label   = 'category';
    $this->options = array();

  }  
public function options() {
    return FieldOptions::build($this);
  }
  public function option($value, $text, $selected = false) {
    return new Brick('option', $this->i18n($text), array(
      'value'    => $value,
      'selected' => $selected
    ));
  }
  	public function input() {
  		$select = new Brick('select');
  		$select->addClass('selectbox');
  		$select->attr(array(
	      'name'         => $this->name(),
	      'id'           => $this->id(),
	      'required'     => $this->required(),
	      'autocomplete' => $this->autocomplete(),
	      'autofocus'    => $this->autofocus(),
	      'readonly'     => $this->readonly(),
	      'disabled'     => $this->disabled(),
	    ));
  	    
    $select = $select->append($this->option('', '', $this->value() == ''));

  	
  	if($this->readonly()) {
      $select->attr('tabindex', '-1');
    }

//this part uses a field with a comma separated list, replace this with the structure field
    if($this->page()->parent()->categories() != "") {
      $categories = $this->page()->parent()->categories()->split();
    }
    else  {
      $categories = site()->categories()->split();
    }
   
    foreach($categories as $category)  {
      $this->options[$category] = $category;
    }

    foreach($this->options() as $value => $text) {
      $select->append($this->option($value, $text, $this->value() == $value));
    }

    $inner = new Brick('div');
    $inner->addClass('selectbox-wrapper');
    $inner->append($select);

    $wrapper = new Brick('div');
    $wrapper->addClass('input input-with-selectbox');
    $wrapper->append($inner);

    if($this->readonly()) {
      $wrapper->addClass('input-is-readonly');
    } else {
      $wrapper->attr('data-focus', 'true');
    }

    return $wrapper;
  	
  }

}
1 Like

Not sure i undrstand sorry, how do i add that field to the blueprint after i create it?
I need the select field in the panel, on the page inside the main one. It isnt for the frontend.
Isnt there any option on this page that does that?
http://getkirby.com/docs/cheatsheet/panel-fields/select
Ive been trying but the select keeps coming up empty.

What you need to do:

  1. Save the above file in site/fields/category as category.php
  2. In your subpage blueprint, use type “category” instead of “select”
1 Like

ok i got it to work but it just shows one option with all the categories like this:

  • categoria: Painting - categoria: Design - categoria: Webdesign - categoria: Filmography

Sorry for being a noob but this is getting a bit complex for what i thought i would need to know when i bought kirby.

Try this

<?php

class CategoryField extends BaseField {

  public function __construct() {
    $this->type    = 'category';
    $this->icon    = 'chevron-down';
    $this->label   = 'category';
    $this->options = array();

  }  
public function options() {
    return FieldOptions::build($this);
  }
  public function option($value, $text, $selected = false) {
    return new Brick('option', $this->i18n($text), array(
      'value'    => $value,
      'selected' => $selected
    ));
  }
  	public function input() {
  		$select = new Brick('select');
  		$select->addClass('selectbox');
  		$select->attr(array(
	      'name'         => $this->name(),
	      'id'           => $this->id(),
	      'required'     => $this->required(),
	      'autocomplete' => $this->autocomplete(),
	      'autofocus'    => $this->autofocus(),
	      'readonly'     => $this->readonly(),
	      'disabled'     => $this->disabled(),
	    ));
  	    
    $select = $select->append($this->option('', '', $this->value() == ''));

    
  	
  	if($this->readonly()) {
      $select->attr('tabindex', '-1');
    }

    if($this->page()->parent()->categorias()) {
      $categories = $this->page()->parent()->categorias()->toStructure();
    }
   
    foreach($categories as $category)  {
      $category = $category->categoria();
      $this->options[] = $category;
    }

    foreach($this->options() as $value => $text) {
      $select->append($this->option($value, $text, $this->value() == $value));
    }

    $inner = new Brick('div');
    $inner->addClass('selectbox-wrapper');
    $inner->append($select);

    $wrapper = new Brick('div');
    $wrapper->addClass('input input-with-selectbox');
    $wrapper->append($inner);

    if($this->readonly()) {
      $wrapper->addClass('input-is-readonly');
    } else {
      $wrapper->attr('data-focus', 'true');
    }

    return $wrapper;
  	
  }

}

Pls note that this will only work with the structure field called “categorias” and the field “categoria” within that structure field. If you rename the field, you have to change this bit of code.

1 Like

Your awesome, thanks.
Only one thing left, it’s returning select number and i need the actual name.

I think these lines

foreach($this->options() as $value => $text) {
      $select->append($this->option($value, $text, $this->value() == $value));

have to be changed to:

foreach($this->options() as $value => $text) {
      $select->append($this->option($text, $text, $this->value() == $text));
    }

Actually, I don’t really know why it does not work to assign the key value pairs in the foreach loop like this:

foreach($categories as $category)  {
      $category = $category->categoria();
      $this->options[$category] = $category;
    }
1 Like

It’s working, thanks for everything.
Hope i don’t get stuck anymore lol
This was probably the hardest part on my template, only problem with this is that categories with spaces break the code, i think ill add 2 fields to the structure, one for display and other for the code itself.

Another way of doing it would be to stick to the numbers as keys and map the keys to the values in your config file and call them via c::get() in your template.

1 Like

I tried to apply this to a page of mine… same structure and idea (select in child pages loading values from a structure field) but I think something has changed since 2.1 update. I’m getting an error:

Warning: Illegal offset type in isset or empty in /Users/me/Sites/mysite/kirby/toolkit/lib/silo.php on line 30

The array manipulation on the code below must be doing something wrong:

if($this->page()->parent()->categorias()) {
  $categories = $this->page()->parent()->categorias()->toStructure();
}
   
foreach($categories as $category)  {
  $category = $category->categoria();
  $this->options[] = $category;
}

foreach($this->options() as $value => $text) {
  $select->append($this->option($value, $text, $this->value() == $value));
}

My blueprint… is using the custom field like:


level:
  label: Difficulty level
  type: category  

Wish i could help, but i’m not using this anymore. I ended up having a page for each category and then use:
category:
label: Additional Category
type: select
options: query
query:
page: work
fetch: children
value: '{{uid}}'
text: ‘{{title}}’

Try this:

<?php

class CategoryField extends BaseField {

  public function __construct() {
    $this->type    = 'category';
    $this->icon    = 'chevron-down';
    $this->label   = 'category';
    $this->options = array();

  }  
public function options() {
    return FieldOptions::build($this);
  }
  public function option($value, $text, $selected = false) {
    return new Brick('option', $this->i18n($text), array(
      'value'    => $value,
      'selected' => $selected
    ));
  }
  	public function input() {
  		$select = new Brick('select');
  		$select->addClass('selectbox');
  		$select->attr(array(
	      'name'         => $this->name(),
	      'id'           => $this->id(),
	      'required'     => $this->required(),
	      'autocomplete' => $this->autocomplete(),
	      'autofocus'    => $this->autofocus(),
	      'readonly'     => $this->readonly(),
	      'disabled'     => $this->disabled(),
	    ));
  	    
    $select = $select->append($this->option('', '', $this->value() == ''));

    
  	
  	if($this->readonly()) {
      $select->attr('tabindex', '-1');
    }

    if(kirby()->site()->event_types()) {
      $event_types = kirby()->site()->event_types()->toStructure();
    }
   
    foreach($event_types as $event_type)  {
      $text = $event_type->event_name();
      $value = $event_type->event_code();
      $keys[] = $value;
      $values[] = $text;
    }
    $this->options = array_combine($keys, $values);
    
    foreach($this->options() as $value => $text) {
      $select->append($this->option($value, $text, $this->value() == $value));
    }

    $inner = new Brick('div');
    $inner->addClass('selectbox-wrapper');
    $inner->append($select);

    $wrapper = new Brick('div');
    $wrapper->addClass('input input-with-selectbox');
    $wrapper->append($inner);

    if($this->readonly()) {
      $wrapper->addClass('input-is-readonly');
    } else {
      $wrapper->attr('data-focus', 'true');
    }

    return $wrapper;
  	
  }

}

Note: This will probably fail if either the event_type or event_name fields are empty, so you would either have to require the fields to be filled in or handle missing fields entries in the code. The external API solution I suggested in this thread Panel: querying "site.txt" structure fields as pages/subpages fields' values is probably the better solution.

Hey, thanks again @texnixe, you’re a life saver.

This new code is giving me the same errors (imagem below)… I’m starting to doubt my local environment (php).

I’ve tried everything I could to fix it, but again… hit a wall :frowning:

[edit] I didn’t invested much on the API solution you’ve mentioned because of the v::url() issue… and also because I didn’t wanted to fiddle with the core (scary stuff).

Haha, found it!

Instead of converting it to kirby objects via toStructure() like you’ve posted:

if(kirby()->site()->event_types()) {
  $event_types = kirby()->site()->event_types()->toStructure();
}

I’ve kept them as arrays all the way, sacrificing the beauty of the kirby way by accessing the associative array directly.

if(kirby()->site()-> event_types()) {
  $event_types = kirby()->site()->event_types()->yaml();
}

foreach($event_types as $event_type)  {
  $text = $event_type['event_name'];
  $value = $event_type['event_code'];
  $keys[] = $value;
  $values[] = $text;
}

Your array manipulation was sound & solid @texnixe :smile:

[edit] Also Regarding the “why using [‘event_code’]”… just found out that when one changes the order in the structure field it changes the selected option in every page/subpage that uses it. So using the “code” will certify that the structure field’s content order won’t matter…

I know it’s been awhile, but I’ve wrapped @texnixe’s code in a nice, portable, and customizable plugin:

1 Like

Thanks for sharing :heart:.