PluginProbe
Contact Forms by Cimatti / 2.2.0
Contact Forms by Cimatti v2.2.0
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.0, at contact-forms.php

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