*/ protected static $submittedMessages = array(); protected $formID = null; protected $buildID = null; protected $validate_functions = array(); protected $submit_functions = array(); protected $elements_sleep; public $stats = array(); protected $accua_ajax; protected $locale = null; protected $language = null; protected $files = array(); protected $ga_track = array(); protected $gads_conversion_tracking_code = ''; protected $original_locale = null; protected $original_language = null; protected $original_l10n = null; protected $forced_language = false; protected $elementsByName = array(); protected $elementCounter = 0; public function force_language() { if ((!$this->forced_language) && $this->language && function_exists('qtrans_getLanguage')) { global $q_config; $this->original_language = $q_config['language']; if ($this->language != $this->original_language) { $this->original_locale =& $GLOBALS['wp_locale']; $this->original_l10n =& $GLOBALS['l10n']; unset($GLOBALS['wp_locale']); unset($GLOBALS['l10n']); $GLOBALS['l10n'] = array(); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- qTranslate plugin integration $GLOBALS['q_config']['language'] = $this->language; load_default_textdomain(); // phpcs:ignore PluginCheck.CodeAnalysis.DiscouragedFunctions.load_plugin_textdomainFound -- Intentionally forces language at runtime for qTranslate email delivery load_plugin_textdomain( 'contact-forms', false, ACCUA_FORM_API_PLUGIN_TEXTDOMAIN_PATH); require_once( ABSPATH . WPINC . '/locale.php' ); $GLOBALS['wp_locale'] = new WP_Locale(); $GLOBALS['wp_locale']->register_globals(); $this->forced_language = true; } } } public function restore_language() { if ($this->forced_language) { unset($GLOBALS['wp_locale']); unset($GLOBALS['l10n']); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- qTranslate plugin integration $GLOBALS['q_config']['language'] = $this->original_language; $GLOBALS['l10n'] =& $this->original_l10n; $GLOBALS['wp_locale'] =& $this->original_locale; if ($GLOBALS['wp_locale']) { $GLOBALS['wp_locale']->register_globals(); } $this->forced_language = false; } } public function __sleep() { $this->elements_sleep = $this->getElements(); return array('attributes', 'elements_sleep', 'error', 'view', 'prefix', 'widthSuffix', 'ajax', 'ajaxCallback', 'jQueryUITheme', 'resourcesPath', 'prevent', 'width', 'formID', 'buildID', 'validate_functions', 'submit_functions', 'stats', 'accua_ajax', 'locale', 'language', 'files'); } public function __wakeup() { foreach ($this->elements_sleep as $element) { $this->addElement($element); } unset($this->elements_sleep); if ($this->view) { $this->view->setForm($this); } if ($this->error) { $this->error->setForm($this); } } public function addElement(Element $element) { $name = $element->getName(); if ($name) { $this->elementsByName[$name] = $element; } $id = $element->getID(); if(empty($id)) { $element->setID($this->attributes["id"] . "-element-" . $this->elementCounter); } $this->elementCounter++; return parent::addElement($element); } public function getElementByName($name) { if (isset($this->elementsByName[$name])) { return $this->elementsByName[$name]; } else { return null; } } public function removeElement($element) { foreach ($this->elements as $k => $e) { if ($e === $element) { $name = $element->getName(); if ($name) { unset ($this->elementsByName[$name]); } unset($this->elements[$k]); return true; } } return false; } public static function sessionID() { $sessionid = session_id(); if ($sessionid === '' && !defined('DOING_CRON')) { $started = session_start(); if (!$started) { $file = $line = ''; if(headers_sent($file,$line)) { error_log("headers already sent at {$file}:{$line}"); } } $sessionid = session_id(); // Close the session immediately after getting the ID to prevent REST API interference session_write_close(); } return $sessionid; } public static function getBaseURL() { static $ret = null; if ($ret === null) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Building internal URL from server variables $s = empty($_SERVER["HTTPS"]) ? '' : (($_SERVER["HTTPS"] == "on") ? "s" : ""); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Building internal URL from server variables $sp = isset($_SERVER["SERVER_PROTOCOL"]) ? strtolower(sanitize_text_field(wp_unslash($_SERVER["SERVER_PROTOCOL"]))) : 'http/1.1'; $protocol = substr($sp, 0, strpos($sp, "/")) . $s; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Building internal URL from server variables $port = (!isset($_SERVER["SERVER_PORT"]) || $_SERVER["SERVER_PORT"] == "80") ? "" : (":" . absint($_SERVER["SERVER_PORT"])); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Building internal URL from server variables $ret = $protocol . "://" . (isset($_SERVER['SERVER_NAME']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_NAME'])) : 'localhost') . $port; } return $ret; } public static function create($baseid = 'pfbc', $params = array()) { if (self::isSubmit() && (!self::isValid()) && ($baseid === self::$submittedID) && (!self::$submittedFormUsed)) { self::$submittedFormUsed = true; if (!(self::isValid() || empty(self::$submittedForm))) { $form = self::$submittedForm; $form->setValues(self::$submittedData); return $form; } $form = new AccuaForm ($baseid, $params, self::$submittedBuildID); $form->setValues(self::$submittedData); } else { $form = new AccuaForm($baseid, $params); } if (function_exists($baseid)) { call_user_func($baseid, $form); } do_action('accua_form_alter', $baseid, $form); return $form; } function __construct($id = 'pfbc', $params = array()) { if (func_num_args() > 2) { $buildid = (string) func_get_arg(2); } else { $buildid = ''; } if ($buildid === '') { $buildid = 'accua-form_' . $id . '_' . uniqid(); } $predefined_params = array( 'width' => '', 'layout' => 'sidebyside', 'title' => '', 'track_submit' => false, 'track_fields' => false, 'gads_conversion_tracking_code' => '', ); if (is_array($params)) { $params += $predefined_params; $width = $params['width']; } else { $width = $params; $params = $predefined_params; $params['width'] = $width; } // Always initialize the property to avoid undefined property warnings $this->gads_conversion_tracking_code = $params['gads_conversion_tracking_code']; $class = 'accua-form ' . $id; switch ($params['layout']) { case 'toplabel': $this->view = new AccuaForm_View_Standard(); $class .= ' accua-form-view-standard'; break; case 'inlinelabel': $this->view = new AccuaForm_View_InlineLabel(); $class .= ' accua-form-view-inlinelabel'; // Prevent PFBC from adding inline width styles for inline label layout $width = ''; break; case 'sidebyside': default: $this->view = new AccuaForm_View_SideBySide( '19', array('labelPaddingRight' => '1') ); $class .= ' accua-form-view-sidebyside'; } $this->error = new AccuaForm_Error_Standard(array( 'errorfound' => '', 'errorsfound' => '', )); // For inline label view, we don't set default width // The CSS handles all widths with width: 100% if ($width === "" && $params['layout'] !== 'inlinelabel'){ $width = "100%"; } $this->attributes = array( 'class' => $class, 'novalidate' => 'novalidate', ); foreach (array('title', 'track_submit', 'track_fields') as $i) { $this->ga_track[$i] = $params[$i]; } parent::__construct($buildid, $width); $this->formID = $id; $this->buildID = $buildid; $this->addElement(new Element_Hidden('_AccuaForm_ID', $id)); $this->addElement(new Element_Hidden('_AccuaForm_buildID', $buildid)); $this->addElement(new Element_Hidden('_AccuaForm_wpnonce', wp_create_nonce( $buildid ))); $this->addElement(new Element_Hidden('_AccuaForm_jsuuid', '')); $this->addElement(new Element_Hidden('_AccuaForm_referrer', '')); $this->addElement(new Element_Hidden('_AccuaForm_user_agent', '')); $this->addElement(new Element_Hidden('_AccuaForm_platform', '')); $this->addElement(new Element_Hidden('_AccuaForm_tentatives', '0')); $this->addElement(new Element_Hidden('_AccuaForm_submit_method', 'normal')); $this->addElement(new Element_Hidden('_AccuaForm_hash', '')); $this->addElement(new Element_Hidden('_AccuaForm_iv', '')); $this->addElement(new Element_Hidden('_AccuaForm_data', '')); /* * - Prima di generare l'html del form, salva una copia serializzata compreso di codice SHA2, criptato, in _AccuaForm_serialized * - Quando ricevi il form, decripta _AccuaForm_serialized e controlla che sia valido * * */ $this->prevent = array('jQuery', 'jQueryUI', 'jQueryUIButtons', 'focus', 'style'); $this->configure(array('action' => '#')); if (function_exists('qtrans_getLanguage')) { $this->language = qtrans_getLanguage(); $this->locale = $GLOBALS['q_config']['locale'][$this->language]; } else { $this->locale = get_locale(); $this->language = explode('_', $this->locale); $this->language = $this->language[0]; } global $post; $pid = empty($post->ID) ? 0 : $post->ID; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- URL stored for logging, escaped on output $uri = isset($GLOBALS['q_config']['url_info']['original_url']) ? $GLOBALS['q_config']['url_info']['original_url'] : (isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : ''); $url = self::getBaseURL() . $uri ; // Set the form action to the current page URL so non-AJAX forms submit cleanly // (AJAX forms override this later in the JS to admin-ajax.php) $this->configure(array('action' => $url)); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Referrer stored for logging, escaped on output $referrer = isset($_SERVER['HTTP_REFERER']) ? esc_url_raw(wp_unslash($_SERVER['HTTP_REFERER'])) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- IP stored for logging, escaped on output $remote_addr = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : ''; $this->stats = array( 'pid' => $pid, 'ip' => $remote_addr, //updated after submit 'original_ip' => $remote_addr, //unreliable if using a static page caching system 'uri' => $uri, 'url' => $url, 'referrer' => $referrer, //updated after submit using javascript 'original_referrer' => $referrer, //unreliable if using a static page caching system 'lang' => $this->language, 'locale' => $this->locale, 'created' => time(), 'submitted' => null, 'user_agent' => '', 'platform' => '', 'tentatives' => '', 'submit_method' => '', ); $this->view->setForm($this); $this->error->setForm($this); } public static function isSubmit() { if (self::$submitted !== null) { return self::$submitted; } self::$submitted = false; $sessid = self::sessionID(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Checking request method for form handling $request_method = isset($_SERVER['REQUEST_METHOD']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_METHOD'])) : 'GET'; if ($request_method === 'POST') { self::$rawData = stripslashes_deep($_POST); } else { self::$rawData = stripslashes_deep($_GET); } // Ensure basic fields for nonce verification are present. if (empty(self::$rawData['_AccuaForm_buildID']) || empty(self::$rawData['_AccuaForm_wpnonce'])) { return false; } // Verify nonce for CSRF protection (moved earlier). // The $id variable (action for nonce) is self::$rawData['_AccuaForm_buildID']. $requested_buildID = self::$rawData['_AccuaForm_buildID']; if (!wp_verify_nonce(self::$rawData['_AccuaForm_wpnonce'], $requested_buildID)) { return false; } // Now check for fields required for form recovery and other validations. if (empty(self::$rawData['_AccuaForm_ID']) || empty(self::$rawData['_AccuaForm_hash']) || empty(self::$rawData['_AccuaForm_iv']) || empty(self::$rawData['_AccuaForm_data'])) { return false; } // $id was self::$rawData['_AccuaForm_buildID'], now using $requested_buildID for clarity. $form = self::wp_recover(self::$rawData['_AccuaForm_hash'], self::$rawData['_AccuaForm_iv'], self::$rawData['_AccuaForm_data']); if (empty($form)) { return false; } if ($form->formID !== self::$rawData['_AccuaForm_ID'] || $form->buildID !== $requested_buildID ) { return false; } /* check if already submitted from uuid and other parameters */ $already_submitted = false; if (!empty(self::$rawData['_AccuaForm_jsuuid'])) { if (preg_match("/^[a-z0-9]{25}$/", self::$rawData['_AccuaForm_jsuuid'])) { $already_submitted_data = get_transient('accuaformsub_'.self::$rawData['_AccuaForm_jsuuid']); if ($already_submitted_data && $already_submitted_data['buildID'] == $form->buildID) { // Only use cached result for successful submissions to prevent duplicate processing if (!empty($already_submitted_data['valid'])) { $form = $already_submitted_data['form']; self::$submittedMessages = $already_submitted_data['submittedMessages']; self::$valid = true; $already_submitted = true; } else { // For failed validations, delete the transient so form can be re-validated // This fixes the bug where correcting a field and resubmitting caused form to disappear delete_transient('accuaformsub_'.self::$rawData['_AccuaForm_jsuuid']); } } } else { return false; } } if (!$already_submitted) { $form->stats['submitted'] = time(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- IP stored for logging, escaped on output $form->stats['ip'] = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : ''; foreach (array('referrer', 'jsuuid', 'user_agent', 'platform', 'tentatives', 'submit_method') as $i){ $form->stats[$i] = isset(self::$rawData["_AccuaForm_{$i}"]) ? ((string)self::$rawData["_AccuaForm_{$i}"]) : ''; } } self::$submitted = true; self::$submittedID = $form->formID; self::$submittedBuildID = $form->buildID; self::$submittedForm = $form; return true; } public static function isValid($id = "pfbc", $clearValues = true) { if (!self::isSubmit()){ return null; } if (self::$valid !== null) { return self::$valid; } //$subdata = array(); $id = self::$submittedBuildID; //$form = self::wp_recover($id); $form = self::$submittedForm; $valid = true; $form->force_language(); /*Any values/errors stored in the session for this form are cleared.*/ self::clearValues($id); self::clearErrors($id); self::$submittedData = array(); /*Each element's value is saved in the session and checked against any validation rules applied to the element.*/ $elements = $form->getElements(); if(!empty($elements)) { foreach($elements as $element) { $invalidFile = false; $name = $element->getName(); if(substr($name, -2) == "[]") { $name = substr($name, 0, -2); } /*The File element must be handled differently b/c it uses the $_FILES superglobal and not $_GET or $_POST.*/ if($element instanceof AccuaForm_Element_File) { if (!empty($form->files[$name]['name'])) { $value = $form->files[$name]['name']; // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- File handling uses $_FILES, nonce verified earlier } else if ((!empty($_FILES[$name])) && (isset($_FILES[$name]['error']) && $_FILES[$name]['error'] != UPLOAD_ERR_NO_FILE)) { //$file = $_FILES[$name]; //include_once( ABSPATH . '/wp-admin/includes/file.php' ); //$overrides = array( 'test_form' => false ); //$file = wp_handle_upload( $file, $overrides ); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- File array passed to WordPress handler $file = $element->handle_upload($_FILES[$name]); $value = $file['name']; if (empty($file['errors'])) { $form->files[$name] = $file; } else { self::setError($id, $file['errors'] , $name); $valid = false; $invalidFile = true; } } else { $value = null; } } else if ($element instanceof Element_File){ // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Legacy file handling $value = isset($_FILES[$name]["name"]) ? sanitize_file_name($_FILES[$name]["name"]) : ''; } else if (isset(self::$rawData[$name])) { $value = self::$rawData[$name]; if(is_array($value)) { foreach($value as $key => $value_i) { // Sanitize null bytes to prevent mail() ValueError in PHP 8+ $value[$key] = str_replace("\0", '', (string) $value_i); } } else { // Sanitize null bytes to prevent mail() ValueError in PHP 8+ $value = str_replace("\0", '', (string) $value); } } else { $value = null; } //self::setSessionValue($id, $name, $value); /*If a validation error is found, the error message is saved in the session along with the element's name.*/ if(!$element->isValid($value)) { self::setError($id, $element->getErrors(), $name); $valid = false; if ($element instanceof AccuaForm_Element_File) { $invalidFile = true; } } if($invalidFile) { // File cleanup is handled in handle_upload() when validation fails // The uploaded tmp file is already deleted by PHP after request completes unset($form->files[$name]); } else if($name !== '') { self::$submittedData[$name] = $value; } } } $_SESSION["pfbc"][$id]["values"] = self::$submittedData; if (function_exists(self::$submittedID.'_validate')) { $valid = call_user_func(self::$submittedID.'_validate', $valid, self::$submittedID, self::$submittedData, $form); } $valid = apply_filters('accua_form_validate', $valid, self::$submittedID, self::$submittedData, $form); asort($form->validate_functions); foreach($form->validate_functions as $func => $priority){ if (function_exists($func)) { $valid = call_user_func($func, $valid, self::$submittedID, self::$submittedData, $form); } } if ($valid) { if (function_exists(self::$submittedID.'_submit')) { call_user_func(self::$submittedID.'_submit', self::$submittedID, self::$submittedData, $form); } do_action('accua_form_submit', self::$submittedID, self::$submittedData, $form); asort($form->submit_functions); foreach($form->submit_functions as $func => $priority){ if (function_exists($func)) { call_user_func($func, self::$submittedID, self::$submittedData, $form); } } } /*Apply errors from session to form elements for accessibility (ARIA attributes). This must be done BEFORE session_write_close() is called, so errors persist in element objects.*/ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Session data for form error handling if (!$valid && !empty($_SESSION["pfbc"][$id]["errors"])) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Session data for form error handling $sessionErrors = $_SESSION["pfbc"][$id]["errors"]; $elements = $form->getElements(); if (!empty($elements)) { foreach ($elements as $element) { $name = $element->getName(); if (substr($name, -2) == "[]") $name = substr($name, 0, -2); if (isset($sessionErrors[$name]) && is_array($sessionErrors[$name])) { $element->setErrors($sessionErrors[$name]); } } } } $form->restore_language(); /*Store form with errors in transient for accessibility on redirect. Both successful and failed submissions are stored so the form can be properly re-rendered with ARIA attributes.*/ if (self::$rawData['_AccuaForm_jsuuid'] ) { set_transient('accuaformsub_'.self::$rawData['_AccuaForm_jsuuid'], array( 'buildID' => self::$submittedBuildID, 'form' => self::$submittedForm, 'submittedMessages' => self::$submittedMessages, 'valid' => $valid, ), 86400); } return self::$valid = (bool)$valid; } public static function getSubmittedData() { self::isValid(); return self::$submittedData; } public static function getSumbittedID() { trigger_error('Use getSubmittedID() instead', (defined('E_USER_DEPRECATED')?E_USER_DEPRECATED:E_USER_NOTICE)); return self::getSubmittedID(); } public static function getSubmittedID() { if (self::isSubmit()) { return self::$submittedID; } else { return null; } } public static function getSubmittedForm() { if (self::isSubmit()) { return self::$submittedForm; } else { return null; } } /*This method restores the serialized form instance.*/ protected static function wp_recover($hash,$iv,$data) { /* if(!empty($_SESSION["pfbc"][$id]["form"])) return unserialize($_SESSION["pfbc"][$id]["form"]); */ /* $storename = 'accua_form_' . md5($id); if ($stored = get_transient($storename)) { return unserialize($stored); } */ $keys = get_option('accua_form_api_keys', array()); @ $hash = base64_decode($hash); @ $iv = base64_decode($iv); @ $data = base64_decode($data); if (!($hash && $iv && $data)) { return; } if (!class_exists('Crypt_Hash')) { require_once('phpseclib-crypt/Hash.php'); } $hasher = new Crypt_Hash('sha1'); $hasher->setKey($keys['hash']); @ $hash2 = $hasher->hash($iv.$data); if ($hash !== $hash2) { return; } if (!class_exists('Crypt_AES')) { require_once('phpseclib-crypt/AES.php'); } $cipher = new Crypt_AES(); $cipher->setPassword($keys['aes']); @ $cipher->setIV($iv); @ $data = $cipher->decrypt($data); if ($data) { @ $form = unserialize($data); if ($form) { return $form; } } } protected function wp_save() { /* $storename = 'accua_form_' . md5($this->buildID); //$serialized = isset($_SESSION["pfbc"][$this->buildID]["form"]) ? $_SESSION["pfbc"][$this->buildID]["form"] : serialize($this); $serialized = serialize($this); set_transient($storename, $serialized, 2764800); // 32 days */ if (!class_exists('Crypt_Hash')) { require_once('phpseclib-crypt/Hash.php'); } if (!class_exists('Crypt_AES')) { require_once('phpseclib-crypt/AES.php'); } $keys = get_option('accua_form_api_keys', array()); if (!(isset($keys['aes']) && isset($keys['hash']))) { accua_form_api_install(); $keys = get_option('accua_form_api_keys', array()); } $data = serialize($this); $iv = wp_generate_password(64,true,true); $cipher = new Crypt_AES(); $cipher->setPassword($keys['aes']); $cipher->setIV($iv); $data = $cipher->encrypt($data); $hasher = new Crypt_Hash('sha1'); $hasher->setKey($keys['hash']); $hash = $hasher->hash($iv.$data); $ret = array( '_AccuaForm_hash' => base64_encode($hash), '_AccuaForm_iv' => base64_encode($iv), '_AccuaForm_data' => base64_encode($data), ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Session data for form values if (isset($_SESSION["pfbc"][$this->buildID]["values"])) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Session data for form values $_SESSION["pfbc"][$this->buildID]["values"] = $ret + $_SESSION["pfbc"][$this->buildID]["values"]; } $this->setValues($ret); return $ret; } public function getLocale() { return $this->locale; } public function getLanguage() { return $this->language; } public function addValidateFunction($function_name, $priority = 0) { $this->validate_functions[$function_name] = $priority; } public function addSubmitFunction($function_name, $priority = 0) { $this->submit_functions[$function_name] = $priority; } /** * Get submitted messages for a specific form or all forms. * @param string|null $formId Optional form ID to get message for specific form * @return string|array If $formId provided, returns string message (or empty string). Otherwise returns all messages as array. */ public static function getSubmittedMessages($formId = null){ if ($formId !== null) { return isset(self::$submittedMessages[$formId]) ? self::$submittedMessages[$formId] : ''; } // Backwards compatibility: if old code expects a string, join all messages if (is_array(self::$submittedMessages)) { return implode('', self::$submittedMessages); } return self::$submittedMessages; } /** * Set submitted message for a specific form. * @param string $msg The message content * @param string|null $formId Optional form ID. If null, uses currently submitted form ID. * @return string The message that was set */ public static function setSubmittedMessages($msg, $formId = null){ if ($formId === null) { $formId = self::$submittedID ?: '__default__'; } self::$submittedMessages[$formId] = $msg; return $msg; } /** * Append to submitted message for a specific form. * @param string $msg The message content to append * @param string|null $formId Optional form ID. If null, uses currently submitted form ID. * @return string The full message after appending */ public static function appendSubmittedmessages($msg, $formId = null){ if ($formId === null) { $formId = self::$submittedID ?: '__default__'; } if (!isset(self::$submittedMessages[$formId])) { self::$submittedMessages[$formId] = ''; } self::$submittedMessages[$formId] .= $msg; return self::$submittedMessages[$formId]; } protected static function get_anchor_id($id) { static $used_anchor_id = array(); if (substr($id, 0, 14) === '__accua-form__') { $id = substr($id, 14); } $id = preg_replace('/[^a-zA-Z0-9]+/m','_',$id); if (empty($used_anchor_id[$id])) { $used_anchor_id[$id] = 1; } else { $used_anchor_id[$id]++; $id = $id . '-' . $used_anchor_id[$id]; } return $id; } public function render($returnHTML = false) { $this->wp_save(); if($returnHTML) { ob_start(); } parent::render(false); if (!empty($this->accua_ajax)) { $ajax_url = _accua_forms_json_encode(admin_url('admin-ajax.php?action=accua_form_submit')); $submit_fail_message = _accua_forms_json_encode('