Chose virtual pages to be created

Hi to all, have a little question.
I know that on kirby site we have a brilliant guide about how to create virtual pages from CSV or API.

Now I’m wondering if it is possible to import not all items to the collection and have the ability to select with virtual pages that should be created.

For Example I have Airtable database where I collect all Online Casino specifications, Online Slots database. And start creating affiliate sites. This sites could be oriented for different markets for example Germany, Ireland, New Zealand etc.

Is it possible to have the ability to connect sites to airtable database and casinos or games which should be placed for sites?

As how I think it should works, on Casinos or Slots pages (where is all collection items are placed) create settings tab where will be multiselect field wich will get access to database and there I will select wich casinos or games should be created as virtual page.

The second solution is to import all databases and change page status from draft to public, but there is about 1500 online casinos, 15000 games and I think this isn’t good idea collect them on every created affiliate site.

Can I ask for suggestions, how can it be done in better way.
Also this solution should help with updates for many sites from one place. Or even it could be not airtable, but some kirby database site wich will be connected with other sites to send or update information for some collections.

Hm, if you do it like this, you will already have to query all entries.

Wouldn’t it make more sense to assign categories to the Airtable entries and then filter by those categories when you query the API?

It should be simple non-technical mechanic because this data will be used by SEO managers that don’t have any technical knowledges.

I can create some category checks based on country or any other field. But for full control would be great to have ability after high level filtering select casinos, or games manually.

About full query, yes it can be full query but limited in mutliselect field to create or not create virtual pages. I think there should be some function that will check array of casino names and if find relevant create pages for them inside control panel

like here

return [
    'slug'     => $slug,
    'template' => 'animal',
    'model'    => 'animal',
    'num'      => 0,
    // add files
    'files'    => $page ? $page->files()->toArray() : null,
    'content'  => [
        'title'       => $animal['Scientific Name'],
        'commonName'  => $animal['Common Name'],
        'description' => $animal['Description'],
        // add additional fields
        'habitat'     => $page ? $page->habitat()->value() : null,
        'diet'        => $page ? $page->diet()->value() : null,

we check
'files' => $page ? $page->files()->toArray() : null,

there could be some similar function to check data from multiselect field and full database and for all relevant items will be created virtual pages.

Ok, but then you already know what you have to do.

Select the stuff you want to show in the Panel, and then filter your virtual pages by what has been selected.

1 Like

Oki can you not close this topic. If I have some troubles, I will write them here and also will try to write finish result that could be solution for other people

Have some progress with this.

Based on Virtual Pages Cookbook I create this:

On settings page I create field that is looking for json data

            label: Chose crypto exchanges for import
            type: multiselect
              type: api
              url: "{{ site.url }}/crypto-exchanges.json"
              text: "{{ item.content.title }}"
              value: "{{ item.slug }}"

Then made little modifications with virtual page model


class CryptoExchangesPage extends Page
    static $subpages = null;

    public function subpages()
        if (static::$subpages) {
            return static::$subpages;

        return static::$subpages = Pages::factory($this->inventory()['children'], $this);

    public function children()
        if ($this->children instanceof Pages) {
            return $this->children;
        $csv = csv($this->root() . '/crpyto-exchanges.csv', ';');
        $children = array_map(function ($crypto_exchange) {

            $slug = Str::slug($crypto_exchange['Scientific Name']);
            $page = $this->subpages()->find($slug);
                return [
                    'slug'     => $slug,
                    'template' => 'crypto-exchange',
                    'model'    => 'crypto-exchange',
                    'num'      => 0,
                    'files'    => $page ? $page->files()->toArray() : null,
                    'content'  => [
                        'title'       => $crypto_exchange['Scientific Name'],
                        'commonName'  => $crypto_exchange['Common Name'],
                        'description' => $crypto_exchange['Description'],
                        'name'        => $page ? $page->name()->value() : null
        }, $csv);
        file_put_contents(kirby()->root() . '/crypto-exchanges.json', json_encode($children));

        $json = file_get_contents(kirby()->root() . '/crypto-exchanges.json');
        $json_data = json_decode($json,true);
        $ce_import = site()->ce_import_settings()->split(',');
        $filtered = array_intersect_key($json_data, $ce_import);
        return $this->children = Pages::factory($filtered, $this);


In my template still preset csv import but it will be changed on API import
the main solution is generate json that is based on $children function

file_put_contents(kirby()->root() . '/crypto-exchanges.json', json_encode($children));

then I get data from generated json and also get field values from settings that I’m checked to be generated as virtual pages

$json = file_get_contents(kirby()->root() . '/crypto-exchanges.json');
$json_data = json_decode($json,true);
$ce_import = site()->ce_import_settings()->split(',');

and the last thing is to check arrays and create virtual pages

$filtered = array_intersect_key($json_data, $ce_import);
return $this->children = Pages::factory($filtered, $this);

On demo data from csv all is works
I don’t know how this will be work on big data where will be 1500 items, and also I still didn’t understand how array_intersect_key check slugs with different structure of arrays, I think it may be problem if in json will be similar to slug data in Content field for example.

Maybe there is the way to optimise this code a little to be more correct @texnixe ?

Have a first problem with this solution
This script work when I select uniq items based on slug
But if I add additional field that is repeat in database for example category it shows me only the one first item of array

I mean this
$filtered = array_intersect_key($json_data, $ce_categories);

Is there any solution to check all $json_data items with second array of categories $ce_categories

After this I will need to create some script that will check few parameters from different arrays to import json_data

For example ce_categories and ce_types

First I need to get all items that is have

  • category 1
  • category 3
    and type
  • type 5

Is it possible somehow to do it?

have some solution, but don’t know if it’s correctly done

$filtered = array_filter($json_data, function ($child) use ($ce_categories_import) {
            return in_array($child['content']['category'], $ce_categories_import);
        $filtered2 = array_filter($json_data, function ($child) use ($ce_types_import) {
            return in_array($child['content']['type'], $ce_items_import);
        $filtered3 = array_merge($filtered, $filtered2);
        return $this->children = Pages::factory($filtered3, $this);

If you merge $filtered and $filtered2 anyway, then you might as well use both conditions in your filter in the first place:

$filtered = array_filter(
    fn ($child) => in_array($child['content']['category'], $ce_categories_import) || in_array($child['content']['type'], $ce_items_import)
1 Like

One more question I see in example Merging content sources | Kirby CMS

that some fields of virtual pages could be updated by control panel

'somefield'   => $page ? $page->somefield()->value() : null

But is there any solution to have ability to rewrite imported field with control panel?

something like this

'somefield'   => $crypto-exchange['somefield'] ? $page->somefield()->value() : null

I tried this but have no luck…

And the second question, is there possibility to enable/disable import for some fields similar to my previous function

I will have toggle field with name of key that may be enabled/disabled form import json.
I understand that is possible but have no luck with understanding how to exclude all values from array based on key true/false field.

I will try to explain a little

For example, Im imported data and create virtual pages with filters that we have created before.
But the base will update periodically. So, in future, fields will be rewritten with new info. In this case, if I select some fields that should be updated manually, I wish to have the ability to rewrite imported info with my own info and be safe in future updates that this info does not disappear.