How to create a ‘calculated field’

I can think of two fundamental approaches…

If you want to do the calculations server side (in a model), there’s no way around doing network requests, which aren’t “immediate” but could be actually pretty fast. I think the most straight forward way (least complicated) would be to let people write model functions (but this means it’s not just the blueprint) and then define, in the blueprint, an extended “info field” that loads the model function and declares what the model function needs.

The model function would be something like:

function taxes() {
    return $this->price() * ($this->taxrate() / 100);
}

The blueprint could be something like:

taxesInfo:
  type: superinfo
  text: The taxes are {{page.taxes}} €
  watch: 
    - price
    - taxrate

In the template you can just use the model function, as that falls back to the saved values:

Taxes: <?= $page->taxes() ?> €

On the front end, the field would then watch for changes on the specified other fields. This should be doable by watching the getters on the store. (From the docs I couldn’t decide which would be the correct one). I doubt it, but the worst could be that you need to listen globally for all store actions and filter for “content/update”, kind of like here, but with the advantage that you actually have a field component that gets mounted and unmounted that you can use to start and stop listening for changes.
Once a value changes, you would ping an api endpoint (fields should get one automatically), and on the server you would evaluate the fields text query on a virtual page that has the updated values. Maybe debounce the call…


Another approach would be to have your own query language (kql doesn’t do math), parse it on the backend and give your frontend an abstract syntax tree that could be evaluated by the field in the panel. Eliminating thus the need for api calls. In this case, the field would have its own value that gets calculated on the frontend and then saved in the content file.