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

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