Writing a (panel) plugin or doable out of the box?

Hi there, I was wondering if someone could give me some input as to what would be the best strategy to achieve the following:

I’m currently exploring the feasibility of using Kirby to implement a grading system for assignments. One of the things I’m trying to determine if it’s possible to calculate a final grade based on the values of a set of fields. Can this be done with a hook and an existing field or should I go the route of writing my own plugin?

You can do this in a model, or if you need it in multiple page types, a [page method] (or extend a model for multiple page type).(Page methods | Kirby CMS). You could even do it “on the fly” using the map() method, but I’d go with one of the first two options.

Do you want to show the result of the calculation in the Panel as well or only on the frontend? The easiest way to show such a custom value in the Panel would be an info field (maybe with custom styles), but you might want to create a stylish custom section to display such result, it depends on what you want to achieve.

Hi Texnixe, ideally both in the panel as well as on the frontend. In my use case Panel would be the environment in which teachers grade assignments, whereas the frontend would be where students review their results.

Right now I have a rudimentary version going of what I had in mind:

site/blueprints/pages/gradingform.yml

title: GradingForm

sections:
  gradingform:
    type: fields
    fields:
      finalGrade:
        label: Final Grade
        type: info
        text: "{{ page.finalgrade }}"
      c1:
        label: Content
        type: select
        help: The student has demonstrated knowledge of how to create pages and how to fill them with content.
        options:
          - value: '0'
            text: Insufficient
          - value: '6'
            text: Sufficient
          - value: '8'
            text: Good
          - value: '10'
            text: Excellent
      c2:
        label: Templates
        type: select
        help: The student has demonstrated knowledge of how to use Kirbys template system and API and built a demonstration template.
        options:
          - value: '0'
            text: Insufficient
          - value: '6'
            text: Sufficient
          - value: '8'
            text: Good
          - value: '10'
            text: Excellent
      c3:
        label: Blueprints
        type: select
        help: The student has demonstrated knowledge of how to create forms for the Panel and acces blueprints on the frontend.
        options:
          - value: '0'
            text: Insufficient
          - value: '6'
            text: Sufficient
          - value: '8'
            text: Good
          - value: '10'
            text: Excellent

site/models/gradingform.php

<?php

    class GradingFormPage extends Page
    {

        public function finalgrade()
        {
            $c1 = $this->c1()->toInt($default = 0);
            $c2 = $this->c2()->toInt($default = 0);
            $c3 = $this->c3()->toInt($default = 0);

            return ($c1+$c2+$c3)/3;
        }

    }

This calculates the final grade on a hard refresh in the panel. How would I go about calling the finalgrade function as the value of one of the select fields in changed by the user?

If you want to react directly on user input (without waiting for save), then you need to use JavaScript to update the finalgrade field in the client. That would probably mean a custom field that listens for changes in one of the other fields.

That makes sense, I guess. Is it possible to call a page method from JS using the API? Otherwise I’d end up with two sets of grading logic (one on the JS side, one on the model side).

No, but you can call the page method in a custom API route endpoint that you call in your script.

Edit: However, to make this work, you would have to pass all values in the request which would make your current model method useless, because it doesn’t accept any parameters. This would be necessary because the server doesn’t know anything of the client side values before they are stored.

I actually think it would more sense in this case to simply calculate the finalgrade again it in the client.

Nice examples, btw.:heart_eyes: (although setting the default to 0 for empty fields really brings down the finalgrade)