Frontend form assistance

Hi All,

I am having some trouble using OJS Frontend Forms. I started by following the instructions as shown on this page:
I wasn’t able to get that to work, partly due to me being a noob, but there are some errors in the documentation that cause it not work work too. Instead of that I created a Bootstrap 5 form with local validation, which worked, but isn’t secure. I quickly came to realise that the validation on my form wasn’t going to be sufficient so I reverted to using OJS forms, but tried to use a different example instead.

The other example of form code was taken from here: lib/pkp/pages/user/

There are significant differences between these two examples and I was wondering which would be the best to follow for a real-world frontend form with validation and captcha.

My plugin displays the form, which is not using $this-addField() but a .tpl file, the contents of which are:

    window.addEventListener("DOMContentLoaded", function(){
{include file="frontend/components/header.tpl" pageTitle="plugins.generic.RCVSKClinicalQueries.RCVSKClinicalQueries"}

 <div class="container pt-5 pb-5">
     <div class="row">
        <div class="col-12">{include file="frontend/components/breadcrumbs.tpl" currentTitleKey="plugins.generic.RCVSKClinicalQueries.RCVSKClinicalQueriesSubmit"}
            <h1 id="clinical-queries" class="h5 fs-3">
                {translate key="plugins.generic.RCVSKClinicalQueries.RCVSKClinicalQueriesSubmit"}
        <div class="col-12">
             <section aria-labelledBy="clinical-queries">
                 <div class="page page_about">
                    <div class="pt-3 pb-3">
                 </div><!-- .page -->
             <section aria-label="Submit Clinical Queries">
                <div class="container px-5 my-5">
                    <form class="pkp_form" id="clinicalQuerySubmitForm" method="post" action="{url op="submitQuery"}" novalidate>
                        {* Help Link *}
                        {help file="user-profile" class="pkp_help_tab btn btn-primary mb-2"}
                        {include file="controllers/notification/inPlaceNotification.tpl" notificationId="contactFormNotification"}
                        {fbvFormSection class="mb-2" title="user.firstName" for="firstName"} *
                            {fbvElement type="text" class="form-control mt-1 mb-2" multilingual="true" name="firstName" id="firstName" value="" size=$fbvStyles.size.MEDIUM required=true}
                        {fbvFormSection title="user.surname" for="surname"} *
                            {fbvElement type="text" class="form-control mt-1 mb-2" multilingual="true" name="surname" id="surname" value="" size=$fbvStyles.size.MEDIUM required=true}
                        {fbvFormSection title="" for="email"} *
                            {fbvElement type="email" class="form-control mt-1 mb-2" id="email" value="" size=$fbvStyles.size.MEDIUM required=true}
                    <p><span class="formRequired">{translate key="common.requiredField"}</span></p>
                    {* recaptcha spam blocker *}
                    {if $reCaptchaHtml}
                        <fieldset class="recaptcha_wrapper">
                            <div class="fields">
                                <div class="recaptcha">
                    {fbvFormButtons class="btn btn-primary" hideCancel=true submitText=""}
                {block name="page"}
{include file="frontend/components/footer.tpl"}

The problems I am having are twofold: the first is with the validation - I just can’t seem to get that to work properly. When I submit the form the application crashes with some fatal errors. I am pretty sure this is due to me messing up but I don’t think I’m far away from a solution but I’m struggling to make sense of the examples.

The first question I have is regarding the form action:

<form class="pkp_form" id="clinicalQuerySubmitForm" method="post" action="{url op="submitQuery"}" novalidate>

The {url op=“submitQuery”} action calls the submitQuery function in my plugin handler but that results in a fatal error too:

Fatal error: Uncaught Error: Class 'RCVSKClinicalQueriesSubmitForm' not found in C:\xampp\htdocs\ojs\plugins\generic\rcvskClinicalQueries\ Stack trace: #0 C:\xampp\htdocs\ojs\lib\pkp\classes\core\ RCVSKClinicalQueriesPluginHandler->submitQuery(Array, Object(Request)) #1 C:\xampp\htdocs\ojs\lib\pkp\classes\core\ PKPRouter->_authorizeInitializeAndCallRequest(Array, Object(Request), Array, false) #2 C:\xampp\htdocs\ojs\lib\pkp\classes\core\ PKPPageRouter->route(Object(Request)) #3 C:\xampp\htdocs\ojs\lib\pkp\classes\core\ Dispatcher->dispatch(Object(Request)) #4 C:\xampp\htdocs\ojs\index.php(68): PKPApplication->execute() #5 {main} thrown in C:\xampp\htdocs\ojs\plugins\generic\rcvskClinicalQueries\ on line 84

The code for he submitQuery function is as follows:-

function submitQuery($args, $request)
    $request = Application::get()->getRequest();
    $templateMgr = TemplateManager::getManager($request);
    $context = Application::get()->getRequest()->getContext();

    // The URL where the form will be submitted
    $apiUrl = $request
        'contexts/' . $context->getId()    // *IS this the correct path??*

    // Get a key/map of the locale keys and names supported by this context.  (Note we have only one locale currently)
    $localeNames = $context->getSupportedFormLocaleNames();
    $locales = [];
    foreach ($localeNames as $key => $name) {
      $locales[] = [
        'key' => $key,
        'label' => $name,
    // Create an instance of the query form
    $queryForm = new RCVSKClinicalQueriesSubmitForm($apiUrl, $locales, $context); // CRASHES HERE
      'components' => [
        FORM_CLINICALQUERY => $queryForm->getConfig(),  // This function wasn't working either so I created a blank one
    return new JSONMessage(true, $queryForm->fetch($request));

Are there any fully-worked-through examples I can use to get this working? The documentation is what I would describe as a partial example, leaving much up to guesswork.

Or perhaps you can see an obvious issue with the code I am using and can suggest a solution?

I appreciate any help I can get here as I feel very close to a solution but am stumped at the last hurdle.

I am using OJS on one server and on the other.