add_help_tab(array( 'id' => 'accua_help_tab', 'title' => __('Contact Forms Dashboard', 'contact-forms'), 'content' => '
' . __('Marketing tools for WordPress', 'contact-forms') . '
', )); wp_enqueue_script( 'accua-forms-expandable-cells', plugins_url( 'assets/js/admin/expandable-cells.js', ACCUA_FORMS_FILE ), array(), ACCUA_FORMS_JS_VERSION, true ); wp_enqueue_script('accua-forms-set-lead-status', plugins_url('assets/js/admin/set-lead-status.js', ACCUA_FORMS_FILE), array('jquery'), ACCUA_FORMS_JS_VERSION, true); wp_enqueue_script('accua_chart_js', plugins_url('assets/vendor/chartjs/chart.umd.min.js', ACCUA_FORMS_FILE), array('jquery'), ACCUA_FORMS_JS_VERSION, true); wp_enqueue_style('accua-forms-admin', plugins_url('assets/css/admin.css', ACCUA_FORMS_FILE), array(), ACCUA_FORMS_CSS_VERSION); /* Tentativo x drag and drop $page_hook_id = fx_smb_setings_page_id(); /* Load the JavaScript needed for the settings screen. * / add_action( 'admin_enqueue_scripts', 'fx_smb_enqueue_scripts' ); add_action( "admin_footer-{$page_hook_id}", 'fx_smb_footer_scripts' ); /* Set number of column available. * / add_filter( 'screen_layout_columns', 'fx_smb_screen_layout_column', 10, 2 ); */ } /** * Add Contact Forms dashboard widget. * * Only visible to users with the 'manage_options' capability, the same * capability required by the plugin admin pages. wp_dashboard_setup only * fires on the dashboard screen, and the widget code is loaded on demand * here, so admin/dashboard-widget.php is never included on the frontend * or on other admin pages. */ add_action('wp_dashboard_setup', 'accua_contact_forms_dashboard_add_widgets'); function accua_contact_forms_dashboard_add_widgets() { if (!current_user_can('manage_options')) { return; } require_once ACCUA_FORMS_DIR . '/admin/dashboard-widget.php'; wp_add_dashboard_widget('accua_contact_forms_dashboard_widget_news', __('Contact Forms', 'contact-forms'), 'accua_contact_forms_dashboard_widget_news_handler'); } function accua_forms_dashboard_page() { require_once ACCUA_FORMS_DIR . '/admin/dashboard-page.php'; return _accua_forms_dashboard_page(); } register_activation_hook(ACCUA_FORMS_FILE, 'accua_forms_install'); function accua_forms_install() { static $ran = false; if ( $ran ) { return; } $ran = true; $modified = false; $keys = get_option('accua_form_api_keys', array()); if (!isset($keys['hash'])) { $modified = true; $keys['hash'] = wp_generate_password(64, true, true); } if (!isset($keys['aes'])) { $modified = true; $keys['aes'] = wp_generate_password(64, true, true); } if ($modified) { update_option('accua_form_api_keys', $keys); } global $wpdb; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); $charset_collate = ''; if (! empty($wpdb->charset)) $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset"; if (! empty($wpdb->collate)) $charset_collate .= " COLLATE $wpdb->collate"; $old_db_version = (int) get_option('accua_forms_db_version', 0); if ($old_db_version < 3) { $wpdb_suppress_errors_status = $wpdb->suppress_errors(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange -- Schema migration, runs once $wpdb->query("ALTER TABLE `{$wpdb->prefix}accua_forms_submissions` DROP INDEX uri"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange -- Schema migration, runs once $wpdb->query("ALTER TABLE `{$wpdb->prefix}accua_forms_submissions` DROP INDEX referrer"); $wpdb->suppress_errors($wpdb_suppress_errors_status); } $sql = "CREATE TABLE `{$wpdb->prefix}accua_forms_submissions` ( afs_id BIGINT(20) NOT NULL AUTO_INCREMENT, afs_form_id VARCHAR(77) NOT NULL DEFAULT '', afs_post_id BIGINT(20) NOT NULL DEFAULT 0, afs_ip VARCHAR(255) NOT NULL DEFAULT '', afs_uri TEXT NOT NULL, afs_referrer TEXT NOT NULL, afs_lang VARCHAR(60) NOT NULL DEFAULT '', afs_created TIMESTAMP NOT NULL DEFAULT 0, afs_submitted TIMESTAMP NOT NULL DEFAULT 0, afs_status TINYINT(1) NOT NULL DEFAULT 0, afs_anonymized TINYINT(1) NOT NULL DEFAULT 0, afs_stats TEXT NOT NULL, afs_lead_status TINYINT(1) NOT NULL DEFAULT 0, PRIMARY KEY (afs_id), KEY form (afs_form_id, afs_status), KEY uri (afs_uri(190)), KEY pid (afs_post_id), KEY referrer (afs_referrer(190)), KEY status (afs_status, afs_id), KEY submitted (afs_submitted), KEY lead_status (afs_lead_status, afs_status) ) $charset_collate;"; dbDelta($sql); $sql = "CREATE TABLE `{$wpdb->prefix}accua_forms_submissions_values` ( afsv_sub_id BIGINT(20) NOT NULL, afsv_field_id VARCHAR(77) NOT NULL, afsv_type varchar(255) NOT NULL DEFAULT '', afsv_value TEXT NOT NULL, PRIMARY KEY (afsv_sub_id, afsv_field_id), KEY value_index (afsv_field_id(77), afsv_value(114)) ) $charset_collate;"; dbDelta($sql); /* creazione tabella per le note dell'utente sono relative a una compilazione possono esserci più note per ogni compilazione in date diverse */ $sql = "CREATE TABLE `{$wpdb->prefix}accua_forms_submissions_notes` ( afsn_sub_id BIGINT(20) NOT NULL, afsn_date TIMESTAMP NOT NULL DEFAULT 0, afsn_text TEXT NOT NULL, afsn_user VARCHAR(100) NOT NULL DEFAULT '', PRIMARY KEY (afsn_sub_id, afsn_date), KEY afsn_sub_id (afsn_sub_id) ) $charset_collate;"; dbDelta($sql); // DB 18: make field slugs case-sensitive in the submission values table. // Runs right after dbDelta, so a fresh install (version 0) is converted at // creation time too. // // Deliberately NOT gated on the stored DB version: dbDelta above rewrites // afsv_field_id back to the table's default (case-insensitive) collation // whenever it runs, because the column no longer matches the definition it // compares against. install() runs on every version change AND on every // activation, so a version check here would leave the column case-insensitive // again after the next update or a deactivate/reactivate - with the values of // two case-differing slugs silently colliding once more. The conversion is // idempotent and returns early when the collation is already binary, so // re-asserting it on each run costs one information_schema lookup. accua_forms_make_field_slugs_case_sensitive(); // Data migration: run after dbDelta so new columns exist if ($old_db_version < 14) { // Migrate: afs_status=-2 (old "anonymized" status) → afs_anonymized=1 + restore original active status // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- One-time migration $wpdb->query("UPDATE `{$wpdb->prefix}accua_forms_submissions` SET afs_anonymized = 1, afs_status = 0 WHERE afs_status = -2"); // Migrate saved forms from 1.x format to 2.0 format $saved_forms = get_option('accua_forms_saved_forms', array()); if (is_array($saved_forms)) { $forms_updated = false; foreach ($saved_forms as $fid => &$form) { // Rename legacy 'name' key to 'title' (changed in 2.0) if (isset($form['name']) && !isset($form['title'])) { $form['title'] = $form['name']; unset($form['name']); $forms_updated = true; } // Convert 'fields' from comma-separated string to array of instances. // Keyed by instance id, exactly as the form editor writes them: the // submission handler looks each posted field up as // $form_data['fields'][$name] (accua-forms.php), so an instance stored // under a numeric key is never found and its value is dropped. if (isset($form['fields']) && is_string($form['fields'])) { $field_slugs = array_filter(array_map('trim', explode(',', $form['fields']))); $form['fields'] = array(); foreach ($field_slugs as $slug) { $istance_id = accua_forms_unique_istance_id($slug, $form['fields']); $form['fields'][$istance_id] = array( 'version' => 2, 'istance_id' => $istance_id, 'widget_number' => '', 'ref' => $slug, 'required' => false, ); } unset($form['fieldnum']); $forms_updated = true; } } unset($form); if ($forms_updated) { update_option('accua_forms_saved_forms', $saved_forms); } } } // DB 19: repair field instances an earlier 1.x -> 2.0 migration left unusable. // That conversion (in 2.0 through 2.3.0) appended array('ref' => $slug) with // no instance id, so the instances ended up under numeric keys. Such a form // still renders - the render loop reads 'ref' - but the submission handler // matches each posted field by array key, finds nothing, and stores the // submission with none of its values. Silent, and only on forms that came // from a pre-2.0 install, which is why it went unnoticed for so long. if ($old_db_version < 19) { accua_forms_repair_field_instances('accua_forms_saved_forms'); // Trashed forms can be restored, so they must come back working too. accua_forms_repair_field_instances('accua_forms_trash_forms'); } // An unreadable field list must never be silently replaced by the defaults: // try to recover it first, and keep a copy of the original either way. accua_forms_recover_avail_fields(); $avail_fields = get_option('accua_forms_avail_fields', array()); if (!is_array($avail_fields)) { $avail_fields = array(); } if (empty($avail_fields) || ($old_db_version === 0)) { $avail_fields += array( // essential_column: shown by the submissions list "Essential Columns" // button - sensible defaults for a contact form: who wrote (name, // email) and what they wrote (message). 'first_name' => array( 'id' => 'first_name', 'name' => 'First Name', 'type' => 'textfield', 'description' => '', 'default_value' => '', 'allowed_values' => '', 'essential_column' => 1, ), 'last_name' => array( 'id' => 'last_name', 'name' => 'Last Name', 'type' => 'textfield', 'description' => '', 'default_value' => '', 'allowed_values' => '', 'essential_column' => 1, ), 'email' => array( 'id' => 'email', 'name' => 'Email', 'type' => 'autoreply_email', 'description' => '', 'default_value' => '', 'allowed_values' => '', 'essential_column' => 1, ), 'address' => array( 'id' => 'address', 'name' => 'Address', 'type' => 'textfield', 'description' => '', 'default_value' => '', 'allowed_values' => '', ), 'city' => array( 'id' => 'city', 'name' => 'City', 'type' => 'textfield', 'description' => '', 'default_value' => '', 'allowed_values' => '', ), 'state_province' => array( 'id' => 'state_province', 'name' => 'State/Province', 'type' => 'textfield', 'description' => '', 'default_value' => '', 'allowed_values' => '', ), 'country' => array( 'id' => 'country', 'name' => 'Country', 'type' => 'select', 'description' => '', 'default_value' => '-', 'allowed_values' => "-|Select... Afghanistan Åland Islands Albania Algeria American Samoa Andorra Angola Anguilla Antarctica Antigua And Barbuda Argentina Armenia Aruba Australia Austria Azerbaijan Bahamas Bahrain Bangladesh Barbados Belarus Belgium Belize Benin Bermuda Bhutan Bolivia Bosnia And Herzegovina Botswana Bouvet Island Brazil British Indian Ocean Territory Brunei Darussalam Bulgaria Burkina Faso Burundi Cambodia Cameroon Canada Cape Verde Cayman Islands Central African Republic Chad Chile China Christmas Island Cocos (Keeling) Islands Colombia Comoros Congo Congo, The Democratic Republic Of The Cook Islands Costa Rica Côte D'Ivoire Croatia Cuba Cyprus Czech Republic Denmark Djibouti Dominica Dominican Republic Ecuador Egypt El Salvador Equatorial Guinea Eritrea Estonia Ethiopia Falkland Islands (Malvinas) Faroe Islands Fiji Finland France French Guiana French Polynesia French Southern Territories Gabon Gambia Georgia Germany Ghana Gibraltar Greece Greenland Grenada Guadeloupe Guam Guatemala Guernsey Guinea Guinea-Bissau Guyana Haiti Heard Island And Mcdonald Islands Holy See (Vatican City State) Honduras Hong Kong Hungary Iceland India Indonesia Iran, Islamic Republic Of Iraq Ireland Isle Of Man Israel Italy Jamaica Japan Jersey Jordan Kazakhstan Kenya Kiribati Korea, Democratic People'S Republic Of Korea, Republic Of Kuwait Kyrgyzstan Lao People'S Democratic Republic Latvia Lebanon Lesotho Liberia Libyan Arab Jamahiriya Liechtenstein Lithuania Luxembourg Macao Macedonia, The Former Yugoslav Republic Of Madagascar Malawi Malaysia Maldives Mali Malta Marshall Islands Martinique Mauritania Mauritius Mayotte Mexico Micronesia, Federated States Of Moldova, Republic Of Monaco Mongolia Montenegro Montserrat Morocco Mozambique Myanmar Namibia Nauru Nepal Netherlands Netherlands Antilles New Caledonia New Zealand Nicaragua Niger Nigeria Niue Norfolk Island Northern Mariana Islands Norway Oman Pakistan Palau Palestinian Territory, Occupied Panama Papua New Guinea Paraguay Peru Philippines Pitcairn Poland Portugal Puerto Rico Qatar Réunion Romania Russian Federation Rwanda Saint Barthélemy Saint Helena Saint Kitts And Nevis Saint Lucia Saint Martin Saint Pierre And Miquelon Saint Vincent And The Grenadines Samoa San Marino Sao Tome And Principe Saudi Arabia Senegal Serbia Seychelles Sierra Leone Singapore Slovakia Slovenia Solomon Islands Somalia South Africa South Georgia And The South Sandwich Islands Spain Sri Lanka Sudan Suriname Svalbard And Jan Mayen Swaziland Sweden Switzerland Syrian Arab Republic Taiwan, Province Of China Tajikistan Tanzania, United Republic Of Thailand Timor-Leste Togo Tokelau Tonga Trinidad And Tobago Tunisia Turkey Turkmenistan Turks And Caicos Islands Tuvalu Uganda Ukraine United Arab Emirates United Kingdom United States United States Minor Outlying Islands Uruguay Uzbekistan Vanuatu Venezuela, Bolivarian Republic Of Viet Nam Virgin Islands, British Virgin Islands, U.S. Wallis And Futuna Western Sahara Yemen Zambia Zimbabwe", ), 'message' => array( 'id' => 'message', 'name' => 'Message', 'type' => 'textarea', 'description' => '', 'default_value' => '', 'allowed_values' => '', 'essential_column' => 1, ), 'captcha' => array( 'id' => 'captcha', 'name' => 'Captcha', 'type' => 'captcha', 'description' => '', 'default_value' => '', 'allowed_values' => '', ), 'turnstile' => array( 'id' => 'turnstile', 'name' => 'Turnstile', 'type' => 'turnstile', 'description' => '', 'default_value' => '', 'allowed_values' => '', ), 'captcha_v3' => array( 'id' => 'captcha_v3', 'name' => 'Captcha (reCAPTCHA v3)', 'type' => 'captcha_v3', 'description' => '', 'default_value' => '', 'allowed_values' => '', ), 'cap' => array( 'id' => 'cap', 'name' => 'Captcha (Cap)', 'type' => 'cap', 'description' => '', 'default_value' => '', 'allowed_values' => '', ), ); update_option('accua_forms_avail_fields', $avail_fields); } // Add Turnstile field for existing installations (backward compatibility) // Only add if it doesn't exist yet if (!isset($avail_fields['turnstile'])) { $avail_fields['turnstile'] = array( 'id' => 'turnstile', 'name' => 'Turnstile', 'type' => 'turnstile', 'description' => '', 'default_value' => '', 'allowed_values' => '', ); update_option('accua_forms_avail_fields', $avail_fields); } // Add reCAPTCHA v3 field for existing installations (backward compatibility) // Only add if it doesn't exist yet if (!isset($avail_fields['captcha_v3'])) { $avail_fields['captcha_v3'] = array( 'id' => 'captcha_v3', 'name' => 'Captcha (reCAPTCHA v3)', 'type' => 'captcha_v3', 'description' => '', 'default_value' => '', 'allowed_values' => '', ); update_option('accua_forms_avail_fields', $avail_fields); } // Add Cap field for existing installations (backward compatibility) // Only add if it doesn't exist yet if (!isset($avail_fields['cap'])) { $avail_fields['cap'] = array( 'id' => 'cap', 'name' => 'Captcha (Cap)', 'type' => 'cap', 'description' => '', 'default_value' => '', 'allowed_values' => '', ); update_option('accua_forms_avail_fields', $avail_fields); } // Add Telephone field for existing installations (backward compatibility) // Only add if it doesn't exist yet if (!isset($avail_fields['telephone'])) { $avail_fields['telephone'] = array( 'id' => 'telephone', 'name' => 'Telephone', 'type' => 'telephone', 'description' => '', 'default_value' => '+39 ', 'allowed_values' => '', ); update_option('accua_forms_avail_fields', $avail_fields); } // 2.2.47 (DB 17): per-field "Show in essential columns" flag. Existing // installations keep the previous behavior of the submissions list // "Essential Columns" button, whose hardcoded list contained one field // column: email. Guarded by isset so a later uncheck (the Fields page save // always writes the key) is never overridden on reactivation; fresh // installs already flag email (and name/message) in the defaults above. if ($old_db_version < 17 && isset($avail_fields['email']) && !isset($avail_fields['email']['essential_column'])) { $avail_fields['email']['essential_column'] = 1; update_option('accua_forms_avail_fields', $avail_fields); } $form_data = get_option('accua_forms_default_form_data', array()); if (!is_array($form_data)) { $form_data = array(); } // Use the centralized defaults function $form_data += accua_forms_get_default_form_data(); update_option('accua_forms_default_form_data', $form_data); update_option('accua_forms_db_version', ACCUA_FORMS_DB_VERSION); } /** * An instance id that is free in this form's field list. * * Field instances are keyed by their instance id, which is normally the field * slug; a form may hold the same field twice, so a taken slug gets a numeric * suffix the way the form editor's own widget numbering does. * * @since 2.3.0 * @param string $slug Field slug the instance refers to. * @param array $fields Instances already placed in this form. * @return string */ function accua_forms_unique_istance_id($slug, $fields) { if (!isset($fields[$slug])) { return $slug; } $n = 2; while (isset($fields[$slug . '-' . $n])) { $n++; } return $slug . '-' . $n; } /** * Give every field instance of every form a usable instance id. * * Instances converted from the pre-2.0 format carry only a 'ref' and sit under * a numeric key, which makes the submission handler drop their values (it looks * each posted field up by array key). Rebuilds those keyed by instance id and * leaves everything else exactly as it is - a normally saved form is untouched, * so this is safe to run over any install and is idempotent. * * @since 2.3.0 * @param string $option Option holding forms ('accua_forms_saved_forms' or the trash). * @return int Number of forms repaired. */ function accua_forms_repair_field_instances($option) { $forms = get_option($option, array()); if (!is_array($forms)) { return 0; } $repaired = 0; foreach ($forms as $fid => $form) { if (empty($form['fields']) || !is_array($form['fields'])) { continue; } // Nothing to do unless some instance is missing its id. $needs_repair = false; foreach ($form['fields'] as $key => $istance_data) { if (!is_array($istance_data) || empty($istance_data['istance_id'])) { $needs_repair = true; break; } } if (!$needs_repair) { continue; } $rebuilt = array(); foreach ($form['fields'] as $key => $istance_data) { // A bare slug instead of an instance: another shape old data turns up in, // and recoverable, so it is rebuilt rather than dropped. if (is_string($istance_data) && '' !== $istance_data) { $istance_data = array('ref' => $istance_data); } if (!is_array($istance_data)) { continue; } if (!empty($istance_data['istance_id'])) { // Already valid: keep it under its own instance id. $rebuilt[$istance_data['istance_id']] = $istance_data; continue; } // The slug is in 'ref'; a numeric key carries no information, but a // string key was the instance id in some hand-edited data, so prefer it. $ref = !empty($istance_data['ref']) ? $istance_data['ref'] : (is_string($key) ? $key : ''); if ('' === $ref) { continue; } $istance_id = accua_forms_unique_istance_id(is_string($key) ? $key : $ref, $rebuilt); $rebuilt[$istance_id] = array( 'version' => 2, 'istance_id' => $istance_id, 'widget_number' => '', 'ref' => $ref, 'required' => !empty($istance_data['required']), ) + $istance_data; } $forms[$fid]['fields'] = $rebuilt; $repaired++; } if ($repaired) { update_option($option, $forms); } return $repaired; } /** * Repair the string lengths of a serialized value whose text was altered * without updating them. * * The usual cause is a migration or search-and-replace tool that rewrote the * option text (classically normalising CRLF to LF) without recomputing the * `s:
|