PluginProbe
Contact Forms by Cimatti / 2.2.32
Contact Forms by Cimatti v2.2.32
2.3.6 2.3.5 2.3.0 2.2.32 2.2.4 2.2.0 2.1.2 2.1.1 trunk 1.0 1.1 1.2 1.2.1 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 All 62 releases
contact-forms / contact-forms.php

contact-forms.php in Contact Forms by Cimatti 2.2.32, at contact-forms.php

930 lines 28.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Contact Forms by Cimatti
4 Description: Create accessible contact forms with drag-and-drop. WCAG 2.2 compliant with screen reader support, keyboard navigation, and clear error messages.
5 Version: 2.2.32
6 Plugin URI: https://www.cimatti.it/en/wordpress-plugins/contact-forms/
7 Author: Cimatti
8 Author URI: https://www.cimatti.it
9 Text Domain: contact-forms
10 Domain Path: /languages
11 Requires at least: 5.9
12 License: GPLv2 or later
13 License URI: http://www.gnu.org/licenses/gpl-2.0.html
14 */
15
16 /*
17 Contact Forms by Cimatti
18 Copyright (c) 2011-2026 Andrea Cimatti
19
20 This program is free software; you can redistribute it and/or
21 modify it under the terms of the GNU General Public License
22 as published by the Free Software Foundation; either version 2
23 of the License, or (at your option) any later version.
24
25 This program is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 GNU General Public License for more details.
29
30 You should have received a copy of the GNU General Public License
31 along with this program; if not, write to the Free Software
32 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
33
34
35 The full copy of the GNU General Public License is available here: http://www.gnu.org/licenses/gpl.txt
36
37 */
38
39 if ( ! defined( 'ABSPATH' ) ) exit;
40
41 define('ACCUA_FORMS_DB_VERSION', '14');
42 define('ACCUA_FORMS_CSS_VERSION', 192);
43 define('ACCUA_FORMS_JS_VERSION', '118');
44 define('ACCUA_FORMS_FILE', __FILE__);
45 define('ACCUA_FORMS_DIR_URL', plugin_dir_url(ACCUA_FORMS_FILE));
46 define('ACCUA_FORMS_DIR', dirname(ACCUA_FORMS_FILE));
47
48 require_once('accua-form-api.php');
49 require_once('accua-forms.php');
50 require_once('admin/shortcode-button.php');
51 require_once('admin/theme-helper.php');
52 require_once('block-editor.php');
53
54 function accua_forms_dashboard_page_head()
55 {
56 $screen = get_current_screen();
57 $screen->add_help_tab(array(
58 'id' => 'accua_help_tab',
59 'title' => __('Contact Forms Dashboard', 'contact-forms'),
60 'content' => '<p>' . __('Marketing tools for WordPress', 'contact-forms') . '</p>',
61 ));
62
63 wp_enqueue_script( 'accua-forms-expandable-cells', plugins_url( 'assets/js/admin/expandable-cells.js', ACCUA_FORMS_FILE ), array(), ACCUA_FORMS_JS_VERSION, true );
64 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);
65 wp_enqueue_style('accua-forms-admin', plugins_url('assets/css/admin.css', ACCUA_FORMS_FILE), array(), ACCUA_FORMS_CSS_VERSION);
66
67 /* Tentativo x drag and drop
68 $page_hook_id = fx_smb_setings_page_id();
69 /* Load the JavaScript needed for the settings screen. * /
70 add_action( 'admin_enqueue_scripts', 'fx_smb_enqueue_scripts' );
71 add_action( "admin_footer-{$page_hook_id}", 'fx_smb_footer_scripts' );
72
73 /* Set number of column available. * /
74 add_filter( 'screen_layout_columns', 'fx_smb_screen_layout_column', 10, 2 );
75 */
76 }
77
78 /**
79 * Add Contact Forms dashboard widget.
80 *
81 * Only visible to users with the 'manage_options' capability, the same
82 * capability required by the plugin admin pages. wp_dashboard_setup only
83 * fires on the dashboard screen, and the widget code is loaded on demand
84 * here, so admin/dashboard-widget.php is never included on the frontend
85 * or on other admin pages.
86 */
87 add_action('wp_dashboard_setup', 'accua_contact_forms_dashboard_add_widgets');
88 function accua_contact_forms_dashboard_add_widgets()
89 {
90 if (!current_user_can('manage_options')) {
91 return;
92 }
93 require_once ACCUA_FORMS_DIR . '/admin/dashboard-widget.php';
94 wp_add_dashboard_widget('accua_contact_forms_dashboard_widget_news', __('Contact Forms', 'contact-forms'), 'accua_contact_forms_dashboard_widget_news_handler');
95 }
96
97 function accua_forms_dashboard_page()
98 {
99 require_once ACCUA_FORMS_DIR . '/admin/dashboard-page.php';
100 return _accua_forms_dashboard_page();
101 }
102
103
104 register_activation_hook(ACCUA_FORMS_FILE, 'accua_forms_install');
105 function accua_forms_install()
106 {
107 static $ran = false;
108 if ( $ran ) {
109 return;
110 }
111 $ran = true;
112
113 $modified = false;
114 $keys = get_option('accua_form_api_keys', array());
115 if (!isset($keys['hash'])) {
116 $modified = true;
117 $keys['hash'] = wp_generate_password(64, true, true);
118 }
119 if (!isset($keys['aes'])) {
120 $modified = true;
121 $keys['aes'] = wp_generate_password(64, true, true);
122 }
123 if ($modified) {
124 update_option('accua_form_api_keys', $keys);
125 }
126
127 global $wpdb;
128
129 require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
130
131 $charset_collate = '';
132 if (! empty($wpdb->charset))
133 $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
134 if (! empty($wpdb->collate))
135 $charset_collate .= " COLLATE $wpdb->collate";
136
137 $old_db_version = (int) get_option('accua_forms_db_version', 0);
138
139 if ($old_db_version < 3) {
140 $wpdb_suppress_errors_status = $wpdb->suppress_errors();
141 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange -- Schema migration, runs once
142 $wpdb->query("ALTER TABLE `{$wpdb->prefix}accua_forms_submissions` DROP INDEX uri");
143 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange -- Schema migration, runs once
144 $wpdb->query("ALTER TABLE `{$wpdb->prefix}accua_forms_submissions` DROP INDEX referrer");
145 $wpdb->suppress_errors($wpdb_suppress_errors_status);
146 }
147
148 $sql = "CREATE TABLE `{$wpdb->prefix}accua_forms_submissions` (
149 afs_id BIGINT(20) NOT NULL AUTO_INCREMENT,
150 afs_form_id VARCHAR(77) NOT NULL DEFAULT '',
151 afs_post_id BIGINT(20) NOT NULL DEFAULT 0,
152 afs_ip VARCHAR(255) NOT NULL DEFAULT '',
153 afs_uri TEXT NOT NULL,
154 afs_referrer TEXT NOT NULL,
155 afs_lang VARCHAR(60) NOT NULL DEFAULT '',
156 afs_created TIMESTAMP NOT NULL DEFAULT 0,
157 afs_submitted TIMESTAMP NOT NULL DEFAULT 0,
158 afs_status TINYINT(1) NOT NULL DEFAULT 0,
159 afs_anonymized TINYINT(1) NOT NULL DEFAULT 0,
160 afs_stats TEXT NOT NULL,
161 afs_lead_status TINYINT(1) NOT NULL DEFAULT 0,
162 PRIMARY KEY (afs_id),
163 KEY form (afs_form_id, afs_status),
164 KEY uri (afs_uri(190)),
165 KEY pid (afs_post_id),
166 KEY referrer (afs_referrer(190)),
167 KEY status (afs_status, afs_id),
168 KEY submitted (afs_submitted),
169 KEY lead_status (afs_lead_status, afs_status)
170 ) $charset_collate;";
171 dbDelta($sql);
172
173 $sql = "CREATE TABLE `{$wpdb->prefix}accua_forms_submissions_values` (
174 afsv_sub_id BIGINT(20) NOT NULL,
175 afsv_field_id VARCHAR(77) NOT NULL,
176 afsv_type varchar(255) NOT NULL DEFAULT '',
177 afsv_value TEXT NOT NULL,
178 PRIMARY KEY (afsv_sub_id, afsv_field_id),
179 KEY value_index (afsv_field_id(77), afsv_value(114))
180 ) $charset_collate;";
181 dbDelta($sql);
182
183 /* creazione tabella per le note dell'utente
184 sono relative a una compilazione
185 possono esserci più note per ogni compilazione in date diverse
186
187 */
188 $sql = "CREATE TABLE `{$wpdb->prefix}accua_forms_submissions_notes` (
189 afsn_sub_id BIGINT(20) NOT NULL,
190 afsn_date TIMESTAMP NOT NULL DEFAULT 0,
191 afsn_text TEXT NOT NULL,
192 afsn_user VARCHAR(100) NOT NULL DEFAULT '',
193 PRIMARY KEY (afsn_sub_id, afsn_date),
194 KEY afsn_sub_id (afsn_sub_id)
195 ) $charset_collate;";
196 dbDelta($sql);
197
198 // Data migration: run after dbDelta so new columns exist
199 if ($old_db_version < 14) {
200 // Migrate: afs_status=-2 (old "anonymized" status) → afs_anonymized=1 + restore original active status
201 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- One-time migration
202 $wpdb->query("UPDATE `{$wpdb->prefix}accua_forms_submissions` SET afs_anonymized = 1, afs_status = 0 WHERE afs_status = -2");
203
204 // Migrate saved forms from 1.x format to 2.0 format
205 $saved_forms = get_option('accua_forms_saved_forms', array());
206 if (is_array($saved_forms)) {
207 $forms_updated = false;
208 foreach ($saved_forms as $fid => &$form) {
209 // Rename legacy 'name' key to 'title' (changed in 2.0)
210 if (isset($form['name']) && !isset($form['title'])) {
211 $form['title'] = $form['name'];
212 unset($form['name']);
213 $forms_updated = true;
214 }
215 // Convert 'fields' from comma-separated string to array of instances
216 if (isset($form['fields']) && is_string($form['fields'])) {
217 $field_slugs = array_filter(array_map('trim', explode(',', $form['fields'])));
218 $form['fields'] = array();
219 foreach ($field_slugs as $slug) {
220 $form['fields'][] = array('ref' => $slug);
221 }
222 unset($form['fieldnum']);
223 $forms_updated = true;
224 }
225 }
226 unset($form);
227 if ($forms_updated) {
228 update_option('accua_forms_saved_forms', $saved_forms);
229 }
230 }
231 }
232
233
234 $avail_fields = get_option('accua_forms_avail_fields', array());
235
236 if (!is_array($avail_fields)) {
237 $avail_fields = array();
238 }
239
240 if (empty($avail_fields) || ($old_db_version === 0)) {
241 $avail_fields += array(
242 'first_name' => array(
243 'id' => 'first_name',
244 'name' => 'First Name',
245 'type' => 'textfield',
246 'description' => '',
247 'default_value' => '',
248 'allowed_values' => '',
249 ),
250 'last_name' => array(
251 'id' => 'last_name',
252 'name' => 'Last Name',
253 'type' => 'textfield',
254 'description' => '',
255 'default_value' => '',
256 'allowed_values' => '',
257 ),
258 'email' => array(
259 'id' => 'email',
260 'name' => 'Email',
261 'type' => 'autoreply_email',
262 'description' => '',
263 'default_value' => '',
264 'allowed_values' => '',
265 ),
266 'address' => array(
267 'id' => 'address',
268 'name' => 'Address',
269 'type' => 'textfield',
270 'description' => '',
271 'default_value' => '',
272 'allowed_values' => '',
273 ),
274 'city' => array(
275 'id' => 'city',
276 'name' => 'City',
277 'type' => 'textfield',
278 'description' => '',
279 'default_value' => '',
280 'allowed_values' => '',
281 ),
282 'state_province' => array(
283 'id' => 'state_province',
284 'name' => 'State/Province',
285 'type' => 'textfield',
286 'description' => '',
287 'default_value' => '',
288 'allowed_values' => '',
289 ),
290 'country' => array(
291 'id' => 'country',
292 'name' => 'Country',
293 'type' => 'select',
294 'description' => '',
295 'default_value' => '-',
296 'allowed_values' => "-|Select...
297 Afghanistan
298 �
299 land Islands
300 Albania
301 Algeria
302 American Samoa
303 Andorra
304 Angola
305 Anguilla
306 Antarctica
307 Antigua And Barbuda
308 Argentina
309 Armenia
310 Aruba
311 Australia
312 Austria
313 Azerbaijan
314 Bahamas
315 Bahrain
316 Bangladesh
317 Barbados
318 Belarus
319 Belgium
320 Belize
321 Benin
322 Bermuda
323 Bhutan
324 Bolivia
325 Bosnia And Herzegovina
326 Botswana
327 Bouvet Island
328 Brazil
329 British Indian Ocean Territory
330 Brunei Darussalam
331 Bulgaria
332 Burkina Faso
333 Burundi
334 Cambodia
335 Cameroon
336 Canada
337 Cape Verde
338 Cayman Islands
339 Central African Republic
340 Chad
341 Chile
342 China
343 Christmas Island
344 Cocos (Keeling) Islands
345 Colombia
346 Comoros
347 Congo
348 Congo, The Democratic Republic Of The
349 Cook Islands
350 Costa Rica
351 Côte D'Ivoire
352 Croatia
353 Cuba
354 Cyprus
355 Czech Republic
356 Denmark
357 Djibouti
358 Dominica
359 Dominican Republic
360 Ecuador
361 Egypt
362 El Salvador
363 Equatorial Guinea
364 Eritrea
365 Estonia
366 Ethiopia
367 Falkland Islands (Malvinas)
368 Faroe Islands
369 Fiji
370 Finland
371 France
372 French Guiana
373 French Polynesia
374 French Southern Territories
375 Gabon
376 Gambia
377 Georgia
378 Germany
379 Ghana
380 Gibraltar
381 Greece
382 Greenland
383 Grenada
384 Guadeloupe
385 Guam
386 Guatemala
387 Guernsey
388 Guinea
389 Guinea-Bissau
390 Guyana
391 Haiti
392 Heard Island And Mcdonald Islands
393 Holy See (Vatican City State)
394 Honduras
395 Hong Kong
396 Hungary
397 Iceland
398 India
399 Indonesia
400 Iran, Islamic Republic Of
401 Iraq
402 Ireland
403 Isle Of Man
404 Israel
405 Italy
406 Jamaica
407 Japan
408 Jersey
409 Jordan
410 Kazakhstan
411 Kenya
412 Kiribati
413 Korea, Democratic People'S Republic Of
414 Korea, Republic Of
415 Kuwait
416 Kyrgyzstan
417 Lao People'S Democratic Republic
418 Latvia
419 Lebanon
420 Lesotho
421 Liberia
422 Libyan Arab Jamahiriya
423 Liechtenstein
424 Lithuania
425 Luxembourg
426 Macao
427 Macedonia, The Former Yugoslav Republic Of
428 Madagascar
429 Malawi
430 Malaysia
431 Maldives
432 Mali
433 Malta
434 Marshall Islands
435 Martinique
436 Mauritania
437 Mauritius
438 Mayotte
439 Mexico
440 Micronesia, Federated States Of
441 Moldova, Republic Of
442 Monaco
443 Mongolia
444 Montenegro
445 Montserrat
446 Morocco
447 Mozambique
448 Myanmar
449 Namibia
450 Nauru
451 Nepal
452 Netherlands
453 Netherlands Antilles
454 New Caledonia
455 New Zealand
456 Nicaragua
457 Niger
458 Nigeria
459 Niue
460 Norfolk Island
461 Northern Mariana Islands
462 Norway
463 Oman
464 Pakistan
465 Palau
466 Palestinian Territory, Occupied
467 Panama
468 Papua New Guinea
469 Paraguay
470 Peru
471 Philippines
472 Pitcairn
473 Poland
474 Portugal
475 Puerto Rico
476 Qatar
477 Réunion
478 Romania
479 Russian Federation
480 Rwanda
481 Saint Barthélemy
482 Saint Helena
483 Saint Kitts And Nevis
484 Saint Lucia
485 Saint Martin
486 Saint Pierre And Miquelon
487 Saint Vincent And The Grenadines
488 Samoa
489 San Marino
490 Sao Tome And Principe
491 Saudi Arabia
492 Senegal
493 Serbia
494 Seychelles
495 Sierra Leone
496 Singapore
497 Slovakia
498 Slovenia
499 Solomon Islands
500 Somalia
501 South Africa
502 South Georgia And The South Sandwich Islands
503 Spain
504 Sri Lanka
505 Sudan
506 Suriname
507 Svalbard And Jan Mayen
508 Swaziland
509 Sweden
510 Switzerland
511 Syrian Arab Republic
512 Taiwan, Province Of China
513 Tajikistan
514 Tanzania, United Republic Of
515 Thailand
516 Timor-Leste
517 Togo
518 Tokelau
519 Tonga
520 Trinidad And Tobago
521 Tunisia
522 Turkey
523 Turkmenistan
524 Turks And Caicos Islands
525 Tuvalu
526 Uganda
527 Ukraine
528 United Arab Emirates
529 United Kingdom
530 United States
531 United States Minor Outlying Islands
532 Uruguay
533 Uzbekistan
534 Vanuatu
535 Venezuela, Bolivarian Republic Of
536 Viet Nam
537 Virgin Islands, British
538 Virgin Islands, U.S.
539 Wallis And Futuna
540 Western Sahara
541 Yemen
542 Zambia
543 Zimbabwe",
544 ),
545 'message' => array(
546 'id' => 'message',
547 'name' => 'Message',
548 'type' => 'textarea',
549 'description' => '',
550 'default_value' => '',
551 'allowed_values' => '',
552 ),
553 'captcha' => array(
554 'id' => 'captcha',
555 'name' => 'Captcha',
556 'type' => 'captcha',
557 'description' => '',
558 'default_value' => '',
559 'allowed_values' => '',
560 ),
561 'turnstile' => array(
562 'id' => 'turnstile',
563 'name' => 'Turnstile',
564 'type' => 'turnstile',
565 'description' => '',
566 'default_value' => '',
567 'allowed_values' => '',
568 ),
569 );
570 update_option('accua_forms_avail_fields', $avail_fields);
571 }
572
573 // Add Turnstile field for existing installations (backward compatibility)
574 // Only add if it doesn't exist yet
575 if (!isset($avail_fields['turnstile'])) {
576 $avail_fields['turnstile'] = array(
577 'id' => 'turnstile',
578 'name' => 'Turnstile',
579 'type' => 'turnstile',
580 'description' => '',
581 'default_value' => '',
582 'allowed_values' => '',
583 );
584 update_option('accua_forms_avail_fields', $avail_fields);
585 }
586
587 // Add Telephone field for existing installations (backward compatibility)
588 // Only add if it doesn't exist yet
589 if (!isset($avail_fields['telephone'])) {
590 $avail_fields['telephone'] = array(
591 'id' => 'telephone',
592 'name' => 'Telephone',
593 'type' => 'telephone',
594 'description' => '',
595 'default_value' => '+39 ',
596 'allowed_values' => '',
597 );
598 update_option('accua_forms_avail_fields', $avail_fields);
599 }
600
601 $form_data = get_option('accua_forms_default_form_data', array());
602 if (!is_array($form_data)) {
603 $form_data = array();
604 }
605
606 // Use the centralized defaults function
607 $form_data += accua_forms_get_default_form_data();
608
609 update_option('accua_forms_default_form_data', $form_data);
610 update_option('accua_forms_db_version', ACCUA_FORMS_DB_VERSION);
611 }
612
613 // Runs at init priority 1 (before accua_form_init at priority 5) so the DB schema
614 // is always up to date before form processing begins. Also ensures translations used
615 // in accua_forms_get_default_form_data() are loaded when a fresh install is detected.
616 add_action('init', 'accua_forms_check_db_version_and_update', 1);
617 function accua_forms_check_db_version_and_update()
618 {
619 if ( get_transient( '_accua_forms_data_deleted' ) ) {
620 return;
621 }
622 $db_version = get_option('accua_forms_db_version', '');
623 if (ACCUA_FORMS_DB_VERSION != $db_version) {
624 accua_forms_install();
625 }
626 }
627
628 add_filter('robots_txt', 'accua_forms_robots_txt', 10, 2);
629 function accua_forms_robots_txt($output, $public)
630 {
631 if ($public) {
632 $site_url = wp_parse_url(site_url());
633 $path = (!empty($site_url['path'])) ? $site_url['path'] : '';
634 $output .= "\nUser-agent: *\n";
635 $output .= "Allow: $path/wp-admin/js/\n";
636 $output .= "Allow: $path/wp-admin/css/\n";
637 }
638 return $output;
639 }
640
641 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Internal helper function with underscore prefix
642 function _accua_forms_json_encode($item)
643 {
644 static $version = NULL;
645 if ($version === NULL) {
646 $version = version_compare(PHP_VERSION, '5.3.0', '>=');
647 }
648 if ($version) {
649 return json_encode($item, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);
650 } else {
651 return strtr(
652 json_encode($item),
653 array(
654 '&' => '\\u0026',
655 '<' => '\\u003C',
656 '>' => '\\u003E',
657 )
658 );
659 }
660 }
661
662 /* per ripulire eventuali token impostati nella versione 1.9.4 */
663 function accua_forms_cleanup_meta_tokens()
664 {
665 global $wpdb;
666 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- One-time cleanup on activation
667 $post_ids = $wpdb->get_col("SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_accua_download_token'");
668
669 if (!empty($post_ids)) {
670 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- One-time cleanup on activation
671 $wpdb->query("DELETE FROM {$wpdb->postmeta} WHERE meta_key = '_accua_download_token'");
672 }
673 }
674 register_activation_hook(__FILE__, 'accua_forms_cleanup_meta_tokens');
675
676 // Schedule retention cleanup cron on activation
677 register_activation_hook( __FILE__, 'accua_forms_activate_retention_cron' );
678 function accua_forms_activate_retention_cron() {
679 if ( ! wp_next_scheduled( 'accua_forms_retention_cleanup' ) ) {
680 wp_schedule_event( time(), 'daily', 'accua_forms_retention_cleanup' );
681 }
682 }
683
684 // Clear retention cleanup cron on deactivation
685 register_deactivation_hook( __FILE__, 'accua_forms_deactivate_retention_cron' );
686 function accua_forms_deactivate_retention_cron() {
687 wp_clear_scheduled_hook( 'accua_forms_retention_cleanup' );
688 }
689
690 // Add REST API compatibility
691 add_action('rest_api_init', 'accua_forms_rest_compatibility');
692
693 /**
694 * Ensures proper REST API compatibility by closing any open PHP sessions
695 * This prevents timeouts when WordPress is making internal REST API requests
696 */
697 function accua_forms_rest_compatibility()
698 {
699 // Check if a session is active and close it for REST requests
700 if (session_id() && session_status() === PHP_SESSION_ACTIVE) {
701 session_write_close();
702 }
703
704 // Remove hooks that might interfere with REST API requests
705 remove_action('init', 'accua_forms_init_session', 1);
706 }
707
708 /**
709 * Get the default form data values.
710 *
711 * This function returns all default values for form settings including messages,
712 * email templates, and styling options. Used during installation and for the
713 * "Restore to Default" functionality in the settings page.
714 *
715 * @since 2.0.0-beta.6
716 * @return array Default form data values.
717 */
718 function accua_forms_get_default_form_data()
719 {
720 return array(
721 'success_message' => '<div style="font-family: Arial, Helvetica, sans-serif;">
722 <h2>' . __('Thank you', 'contact-forms') . ' {first_name} {last_name},</h2>
723 ' . __('We have received your contact request. Check your inbox for the confirmation message.', 'contact-forms') . '
724
725 <strong>' . __('Can\'t find the email?', 'contact-forms') . '</strong>
726
727 ' . __('It doesn\'t happen often but your mailbox could apply strict spam rules that block our email from reaching your inbox. Try checking your spam folder.', 'contact-forms') . '
728
729 ' . __('Also check that the email you entered in the form', 'contact-forms') . ' (<strong>{email}</strong>) ' . __('is correct. If it is not, you can submit the form again.', 'contact-forms') . '
730
731 ' . __('For any other issues, please don\'t hesitate to contact us.', 'contact-forms') . '
732
733 </div>',
734 'error_message' => '<div style="font-family: Arial, Helvetica, sans-serif;">
735 <h2>' . __('Oops! Something went wrong.', 'contact-forms') . '</h2>
736 ' . __('Internet is an awfully complex place and even though we take every precaution to make sure things run smoothly every once in a while things can go wrong that are not under our control.', 'contact-forms') . '
737
738 ' . __('Please try filling in the form again.', 'contact-forms') . '
739
740 ' . __('For any other issues, please don\'t hesitate to contact us.', 'contact-forms') . '
741
742 </div>',
743 'emails_from_name' => '',
744 'emails_from' => '',
745 'admin_emails_to' => get_option('admin_email', ''),
746 'emails_bcc' => '',
747 'admin_emails_subject' => __('New contact request from your site', 'contact-forms'),
748 'admin_emails_message' => '<table style="font-family: Arial, Helvetica, sans-serif; background: #fff; margin-top: 10px; border: 1px solid #DDDDDD; max-width: 700px;" cellspacing="0" cellpadding="0" align="center">
749 <tbody>
750 <tr>
751 <td>
752 <table style="max-width:700px;" border="0" cellspacing="0" cellpadding="0" align="center">
753 <tbody>
754 <tr>
755 <td>
756 <table style="padding: 10px; border: 1px solid #dfdfdf; max-width:700px;" border="0" cellspacing="0" cellpadding="0" align="center">
757 <tbody>
758 <tr valign="top">
759 <td style="max-width:22px;"></td>
760 <td style="font-family: Arial, Helvetica, sans-serif; padding: 0px 30px 10px; max-width: 645px;">
761 <table style="width: 100%; table-layout: fixed;">
762 <tbody>
763 <tr>
764 <td>' . __('On', 'contact-forms') . ' {__submitted_day_month_year} ' . __('at', 'contact-forms') . ' {__submitted_hour} ' . __('the following form was filled in.', 'contact-forms') . '
765
766 <hr />
767
768 <strong>' . __('Page where the form was filled in', 'contact-forms') . '</strong>
769 <a href="{__url}" style="word-break: break-all; overflow-wrap: break-word;">{__url}</a></td>
770 </tr>
771 <tr><td>
772 <strong>' . __('Submission review page', 'contact-forms') . '</strong>
773 <a href="{__review_submission_url}" style="word-break: break-all; overflow-wrap: break-word;">{__review_submission_url}</a>
774 </td></tr>
775 <tr>
776 <td id="submitted_html" style="overflow-wrap: break-word; word-break: normal;">{__submitted_html}</td>
777 </tr>
778 <tr>
779 <td>[form_if {__referrer} [<strong>' . __('Referrer', 'contact-forms') . '</strong> - ' . __('where the visitor came from', 'contact-forms') . ' <em>' . __('before reaching the page', 'contact-forms') . '</em>:<br /><span style="word-break: break-all; overflow-wrap: break-word;">{__referrer}</span>]]</td>
780 </tr>
781 <tr>
782 <td><strong>' . __('Contact IP', 'contact-forms') . '</strong> {__anonymized_ip}
783 <hr />
784 </td>
785 </tr>
786 <tr>
787 <td>[form_if {__autoreply} [' . __('A confirmation email was sent to', 'contact-forms') . ' <a href="mailto:{email}">{email}</a> ' . __('with the following message', 'contact-forms') . ':
788 <table>
789 <tbody>
790 <tr>
791 <td>{__confirmation_emails_message}</td>
792 </tr>
793 </tbody>
794 </table> ]]
795 </td>
796 </tr>
797 </tbody>
798 </table>
799 </td>
800 <td style="max-width:23px"></td>
801 </tr>
802 </tbody>
803 </table>
804 </td>
805 </tr>
806 </tbody>
807 </table>
808 </td>
809 </tr>
810 </tbody>
811 </table>',
812 'confirmation_emails_subject' => __('Your message', 'contact-forms'),
813 'confirmation_emails_message' => '<div style="font-family: Arial, Helvetica, sans-serif;">
814
815 <h2>' . __('Thank you', 'contact-forms') . ' {first_name} {last_name},</h2>
816 ' . __('Thank you for your contact request.', 'contact-forms') . '
817
818 ' . __('We will contact you as soon as possible.', 'contact-forms') . '
819
820 ' . __('Sincerely,', 'contact-forms') . '
821
822 ' . __('The Website Team', 'contact-forms') . '
823
824 <hr />
825 </div>',
826
827 'layout' => 'sidebyside',
828 'style_margin' => '',
829 'style_border_color' => '',
830 'style_border_width' => '',
831 'style_border_radius' => '',
832 'style_background_color' => '',
833 'style_padding' => '',
834 'style_color' => '',
835 'style_font_size' => '',
836 'style_field_spacing' => '',
837 'style_field_border_color' => '',
838 'style_field_border_width' => '',
839 'style_field_border_radius' => '',
840 'style_field_background_color' => '',
841 'style_field_padding' => '',
842 'style_field_color' => '',
843 'style_submit_border_color' => '',
844 'style_submit_border_width' => '',
845 'style_submit_border_radius' => '',
846 'style_submit_background_color' => '',
847 'style_submit_padding' => '',
848 'style_submit_color' => '',
849 'style_submit_font_size' => '',
850 );
851 }
852
853 /**
854 * Get all countries with localized names for phone field country selector.
855 *
856 * Uses PHP Intl extension to generate localized country names from ISO 3166-1 alpha-2 codes.
857 * Falls back to country codes if Intl extension is unavailable.
858 *
859 * @since 2.0.0-beta.34
860 * @param string|null $display_locale Locale for display names (default: current WordPress locale).
861 * @return array Associative array ['US' => 'United States', 'IT' => 'Italy', ...] sorted alphabetically.
862 */
863 function accua_forms_get_countries( $display_locale = null ) {
864 // ISO 3166-1 alpha-2 codes - complete list (249 countries/territories)
865 $country_codes = array(
866 'AF', 'AX', 'AL', 'DZ', 'AS', 'AD', 'AO', 'AI', 'AQ', 'AG', 'AR', 'AM', 'AW', 'AU', 'AT', 'AZ',
867 'BS', 'BH', 'BD', 'BB', 'BY', 'BE', 'BZ', 'BJ', 'BM', 'BT', 'BO', 'BQ', 'BA', 'BW', 'BV', 'BR',
868 'IO', 'BN', 'BG', 'BF', 'BI', 'KH', 'CM', 'CA', 'CV', 'KY', 'CF', 'TD', 'CL', 'CN', 'CX', 'CC',
869 'CO', 'KM', 'CG', 'CD', 'CK', 'CR', 'CI', 'HR', 'CU', 'CW', 'CY', 'CZ', 'DK', 'DJ', 'DM', 'DO',
870 'EC', 'EG', 'SV', 'GQ', 'ER', 'EE', 'ET', 'FK', 'FO', 'FJ', 'FI', 'FR', 'GF', 'PF', 'TF', 'GA',
871 'GM', 'GE', 'DE', 'GH', 'GI', 'GR', 'GL', 'GD', 'GP', 'GU', 'GT', 'GG', 'GN', 'GW', 'GY', 'HT',
872 'HM', 'VA', 'HN', 'HK', 'HU', 'IS', 'IN', 'ID', 'IR', 'IQ', 'IE', 'IM', 'IL', 'IT', 'JM', 'JP',
873 'JE', 'JO', 'KZ', 'KE', 'KI', 'KP', 'KR', 'KW', 'KG', 'LA', 'LV', 'LB', 'LS', 'LR', 'LY', 'LI',
874 'LT', 'LU', 'MO', 'MK', 'MG', 'MW', 'MY', 'MV', 'ML', 'MT', 'MH', 'MQ', 'MR', 'MU', 'YT', 'MX',
875 'FM', 'MD', 'MC', 'MN', 'ME', 'MS', 'MA', 'MZ', 'MM', 'NA', 'NR', 'NP', 'NL', 'NC', 'NZ', 'NI',
876 'NE', 'NG', 'NU', 'NF', 'MP', 'NO', 'OM', 'PK', 'PW', 'PS', 'PA', 'PG', 'PY', 'PE', 'PH', 'PN',
877 'PL', 'PT', 'PR', 'QA', 'RE', 'RO', 'RU', 'RW', 'BL', 'SH', 'KN', 'LC', 'MF', 'PM', 'VC', 'WS',
878 'SM', 'ST', 'SA', 'SN', 'RS', 'SC', 'SL', 'SG', 'SX', 'SK', 'SI', 'SB', 'SO', 'ZA', 'GS', 'SS',
879 'ES', 'LK', 'SD', 'SR', 'SJ', 'SZ', 'SE', 'CH', 'SY', 'TW', 'TJ', 'TZ', 'TH', 'TL', 'TG', 'TK',
880 'TO', 'TT', 'TN', 'TR', 'TM', 'TC', 'TV', 'UG', 'UA', 'AE', 'GB', 'US', 'UM', 'UY', 'UZ', 'VU',
881 'VE', 'VN', 'VG', 'VI', 'WF', 'EH', 'YE', 'ZM', 'ZW',
882 );
883
884 // Use WordPress locale if not specified
885 if ( null === $display_locale ) {
886 $display_locale = get_locale();
887 }
888
889 // Check if Intl extension is available
890 if ( ! class_exists( 'Locale' ) ) {
891 // Fallback: return codes as both key and value
892 return array_combine( $country_codes, $country_codes );
893 }
894
895 $countries = array();
896 foreach ( $country_codes as $code ) {
897 // The trick: prepend '-' to convert region code to locale format
898 $name = Locale::getDisplayRegion( '-' . $code, $display_locale );
899 // If Intl returns the code itself (unknown region), use the code
900 $countries[ $code ] = ( $name && $name !== $code ) ? $name : $code;
901 }
902
903 // Sort alphabetically by localized name
904 asort( $countries, SORT_LOCALE_STRING );
905
906 return $countries;
907 }
908
909 /**
910 * Get the translated label for a layout value.
911 *
912 * Returns the human-readable, translated label for a given layout value.
913 * Used in layout dropdowns throughout the admin interface.
914 *
915 * @since 2.0.0-beta.29
916 * @param string $layout Layout value: 'sidebyside', 'toplabel', or 'inlinelabel'.
917 * @return string Translated layout label.
918 */
919 function accua_forms_get_layout_label( $layout ) {
920 switch ( $layout ) {
921 case 'toplabel':
922 return __( 'Labels on top of the fields', 'contact-forms' );
923 case 'inlinelabel':
924 return __( 'Inline labels', 'contact-forms' );
925 case 'sidebyside':
926 default:
927 return __( 'Labels on the left of the fields', 'contact-forms' );
928 }
929 }
930