Panel: querying "site.txt" structure fields as pages/subpages fields' values

Lets start with my intent… I’d like to have (user) configurable options for some of the pages’ fields.

For example, a select field in my “/events/event” blueprint that queries some of the /site.txt fields… which would have the configurable options I’d like to use, preferably a structure field.

This way the panel user would be able to set some options or manage values that were predefined by the developer.

A structure field in site.txt would have:

----

Site-Event-types: 

- 
  event_code: 0
  event_name: 'Meetup'
- 
  event_code: 1
  event_name: 'Workshop'
- 
  event_code: 2
  event_name: 'Lecture'

And the “event” blueprint could have a select field like:

event_type:
  label: Type of event
  type: select
  options: query

  query:
    page: site
    fetch: site_event_types[] # some way to indicate a structure field
    text: '{{event_name}}'
    value: '{{event_code}}' 

The panel would somehow identify all the entries in the structure field, query them and allow the panel user to select one. Notice that “text:” and “value:” each brings a different “subfield” from the structure field off site.txt.

If the panel user selected the second option (Workshop) and saved… the resulting event.txt would have:

----

Event-type:   1

----
... 

This way in my “event” template I’d use:

<?php 
   $types = $site->site_event_type()->yaml(); 

   if( $page->event_type() == $types[1]['event_code'] ) { 

     //retrieve the respective entry name value from $site 
    echo 'Type of event: '.$types[1]['event_name'];

    // prints: Type of event: Workshop
 ?> 

Maybe there’s a way to do it… and my kirby newbieness is keeping me from seeing it… any help would be much appreciated.

Shout out to @texnixe & @distantnative if you guys could take a look please… :confused:

  1. Idea: You could create a custom field that pulls the information from the structure field. But you would need a separate custom field for each field.

  2. Idea:( But I don’t know if panel hooks work when site.txt is updated). Create a hook that writes the options to a json file that is available via URL. Then you could add that URL to the options query.

External API support for dynamic field options

You can now simply pass a URL for options to fetch a JSON array with keys and values for options:

  label: Select field
  type: select
  options: http://myoptionsapi.com/options.json
Make sure the JSON is in the following format:

{
 'key1' : 'value1',
 'key2' : 'value2',
 'key3' : 'value3' 
}

http://getkirby.com/changelog/kirby-2-1-0

Thank you for the ideas… I believe this could be the definitive solution… a plugin (or custom field) that allows a field (select, radio and checkboxes) to query structure fields, be it from site.txt or any other page/subpage.

I thought about using this new json thingy… but then got stuck about where to save it… I don’t want to create a page just to have a place for saving the .json file.

I thought the perfect place would be the assets folder… like
/assets/json/event.json but again have no idea how to access/read it neither how to write it in order to accomplish what i’ve posted above.

For now my options are hardcoded in the “event” blueprint, using a simple select field… and I’m using a controller to translate the values into names… so it’s static and every time the panel user needs a new value I’d have to update the website.

the controller :

<?php
  return function($site, $pages, $page) {
    return array( 'event_type' => array( 
                             0 => 'Meetup', 
                             1 => 'Workshop', 
                             2 => 'Lecture')
    );
  };
?>
 

And in the template I fetch it like:

<p>Event type: <?php echo $event_type[$page->event_type()->int()] ?></p> 

So much to learn… :confused:

Have a look at this thread for a solution for idea no. 1 Fetch query from parent page.

BTW. Is there a reason why you need the code instead of just the name of the event?

I will test the second option, haven’t done it myself yet but would really be useful for lots of similar use cases. I also think it should not be saved in /content but in /assets, but that should not be a problem.

Awesome link… a quite similar problem, will investigate if I can adapt it.

Convenience… I guess (I’m just learning kirby by doing…), if the returned numbers are zero-based (like arrays) and matches those from the structure menu… In the templates I can yaml(), foreach loop and toStructure the thing…

Regarding the panel, special caracters (ç, ã, space, etc.) might get in the way too, and I’d like to use bigger amounts of info, maybe even a textarea field as a subitem of the structure… which I believe would open lots of opportunities.

I’m eagerly awaiting for yours tests @texnixe :smile:

After fiddling with the link you’ve sent. I understood why you asked about the code… the select (when reading the value from de structure field) already returns the item position in the array/structure. I’m dumb.

Anyway… couldn’t figure how to make the custom field work. i keep getting errors like:

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

I’m out of options… and have no idea how to solve this.

[edit] I believe there’s something wrong with the blueprint that’s using the custom select field… I’m using like:

event_type:
    label: Event type
    type: category  
    options: query
      page: events #this is the parent page

I managed to get my second option to work, albeit with one drawback: I can only access the json file when I put it on a remote server, my http://localhost/kirbyisgreat/assets/json/event.json link results in an empty select :sob:

But the file is created in the given folder.

Anyway, here is my rough try at the hook if you want to fiddle some more:

<?php
kirby()->hook('panel.page.update', function($page) {
if($page->intendedTemplate() == "site" ) {
  $events = $page->event_types()->yaml();
  $content = array();
  foreach($events as $event) {
     $key = $event['event_code'];
     $value = $event['event_name'];
     $content[$key] = $value;
  }
  $content = json_encode($content, JSON_FORCE_OBJECT);
  $kirby = kirby();
  $file = $kirby->roots()->index() . '/assets/json/events.json';
  try {
    f::write($file, $content, false);
  } catch (Exception $e) {
      unset($e);
  }
}
});

Of course, you could add some checks and only execute the code when the relevant page is updated and the field exists etc.

Maybe someone has an idea why it doesn’t read the file on localhost or maybe it’s not a localhost problem? Need to check this on a remote server. Any hints at how to optimize the code welcome.

Edit: I think I had come across this problem before, it’s probably the v::url() function at work …
Edit 2: Yes, if I disable v::url() in fieldoptions.php, it also works on localhost.

1 Like

Good work @texnixe, thanks. It’ll sure come handy in lots of contexts.

Have you tested if the hook is triggered when the site.txt is edited?

yes I have and I will edit the code above to only trigger if site.txt is updated … otherwise you will end up with an empty event.json file as soon as another page is updated.

Do you think that the v::url() validation in fieldoptions.php should be reported as an issue when using panel.hooks?

Or are there other implications for it that I’m not aware… just trying to understand…

It has nothing to do with the panel hooks, it’s just when you add a localhost url to the select options instead of a “real” url, it doesn’t validate and so the select will have no options. It makes testing a local “external” API difficult.

The regex used for url validation refers to this page In search of the perfect URL validation regex

Assume that this regex will be used for a public URL shortener written in PHP, so URLs like http://localhost/, //foo.bar/, ://foo.bar/, data:text/plain;charset=utf-8,OHAI and tel:+1234567890 shouldn’t pass (even though they’re technically valid). Also, in this case I only want to allow the HTTP, HTTPS and FTP protocols.

So I don’t know what the best solution would be, @bastianallgeier, in case of the external API options?

Edit: I created an issue on GitHub just in case: v::url() in fieldoptions.php prevents use of "external" query API on localhost · Issue #548 · getkirby-v2/panel · GitHub

The localhost validation issue will be resolved in the upcoming Kirby 2.2 release, already available as beta.

1 Like

Just out of curiosity – I was just thinking about this kind of solution, storing configurable options on the site page.

Is this now possible in the latest Kirby version? I tried, but I cannot get it to work.

I will probably fall back to using the “Option from other field” as described on https://getkirby.com/docs/cheatsheet/panel-fields/checkboxes. It works when I query from the parent page. I can’t get it to work to query from site.txt, unfortunately. Will ask in the forum.

Back then… I had to use Custom form fields and manipulate values/arrays manually as to achieve what I wanted… not sure now with v.2.3 thou.

Thx for the quick feedback!

As I said in the other post, if you want to query a structure field, you would still have to create a custom field.

Just to dredge this topic back up @texnixe — unless I’m missing something, panel.page.update does not run when you update the site settings (I’m using v2.2.3), but panel.site.update does, so I’m hooking into that.

Having successfully written my options to a JSON file, I’m still running into the localhost validation issue mentioned above; options: http://localhost:8000/assets/json/colors.json in my blueprint gives an empty select, but options: http://mysite.com/assets/json/colors.json (with a “real” URL) behaves as expected.

So, 2 questions:

  1. Has the “localhost validation issue” fix made it into a release?

  2. Is there any way to either provide a relative URL to the JSON file in situations like these (when the “external” JSON file is actually one we’re generating for use on-site), or use a placeholder in the blueprint, something like {{site_url}}/assets/json/colors.json so we don’t have to remember to update the URL when moving from staging to production?

Thanks! :slight_smile:

@poisontofu I think the localhost validation issue was fixed a while ago, but I’ll double-check.

Edit: It is said to have been fixed last October: https://github.com/getkirby/panel/issues/548

Thanks for chasing up. I’ll double-check my code and see if I can replicate it on a clean install. Not a huge deal in the scheme of things :slight_smile: