PluginProbe
Duplicate Killer – Prevent Duplicate Form Submissions / trunk
Duplicate Killer – Prevent Duplicate Form Submissions vtrunk
1.7.0 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.9 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 trunk 1.2.1 1.2.2 All 35 releases
duplicate-killer / function.php

function.php in Duplicate Killer – Prevent Duplicate Form Submissions trunk, at function.php

686 lines 25.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: Duplicate Killer
4 * Version: 1.7.0
5 * Description: Block duplicate form submissions by validating unique email, phone and text fields — without CAPTCHA.
6 * Author: NIA
7 * Author URI: https://profiles.wordpress.org/wpnia/
8 * Text Domain: duplicate-killer
9 * License: GPLv2 or later
10 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
11 */
12
13 defined('ABSPATH') or die('You shall not pass!');
14
15 define('DUPLICATEKILLER_PLUGIN',__FILE__);
16 define('DUPLICATEKILLER_VERSION','1.7.0');
17 define('DUPLICATEKILLER_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
18 define('DUPLICATEKILLER_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
19
20 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/helpers.php';
21 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/modern-popup-mode.php';
22 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/dk-cookie-loader.php';
23 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/render.php';
24 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/sanitize.php';
25
26 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/functions_cf7.php';
27 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/functions_forminator.php';
28 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/functions_wpforms.php';
29 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/functions_breakdance.php';
30 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/functions_elementor.php';
31 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/functions_formidable.php';
32 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/functions_ninjaforms.php';
33 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/functions_fluentforms.php';
34
35 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/database.php';
36 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/pro.php';
37
38 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/class-duplicateKiller-woocommerce.php';
39 duplicateKiller_WooCommerce::init();
40
41 //debug/diagnostics
42 require_once DUPLICATEKILLER_PLUGIN_DIR . '/includes/class-duplicateKiller-diagnostics.php';
43 duplicateKiller_Diagnostics::init();
44
45 //uninstall/feedback
46 require_once DUPLICATEKILLER_PLUGIN_DIR . '/uninstall/class-duplicatekiller-deactivation-feedback.php';
47 duplicateKiller_Deactivation_Feedback::init();
48
49 require_once DUPLICATEKILLER_PLUGIN_DIR . '/includes/class-duplicatekiller-form-normalizer.php';
50 require_once DUPLICATEKILLER_PLUGIN_DIR . '/includes/class-duplicatekiller-form-config-resolver.php';
51 require_once DUPLICATEKILLER_PLUGIN_DIR . '/includes/class-duplicatekiller-ip-limit-checker.php';
52 require_once DUPLICATEKILLER_PLUGIN_DIR . '/includes/class-duplicatekiller-fieldduplicate-checker.php';
53 require_once DUPLICATEKILLER_PLUGIN_DIR . '/includes/class-duplicatekiller-submission-storage.php';
54
55 require_once DUPLICATEKILLER_PLUGIN_DIR.'/includes/class-duplicateKiller-cross-form.php';
56
57 //location helpers.php
58 add_action('admin_init', 'duplicateKiller_handle_delete_records_request');
59 add_action('admin_init', 'duplicateKiller_handle_dismiss_milestone_notice');
60 add_action('admin_notices', 'duplicateKiller_admin_review_milestone_notice');
61 /**
62 * Create a new table in db
63 */
64 function duplicateKiller_create_table(){
65 global $wpdb;
66 $table_name = $wpdb->prefix.'dk_forms_duplicate';
67 $charset_collate = $wpdb->get_charset_collate();
68
69 $sql = "CREATE TABLE $table_name (
70 form_id bigint(20) NOT NULL AUTO_INCREMENT,
71 form_plugin varchar(50) NOT NULL,
72 form_name varchar(50) NOT NULL,
73 form_value longtext NOT NULL,
74 form_cookie longtext NOT NULL,
75 form_ip varchar(50) NOT NULL,
76 form_date datetime NOT NULL,
77 PRIMARY KEY (form_id)
78 ) $charset_collate;";
79
80 require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
81 dbDelta( $sql );
82 }
83
84 /**
85 * Activation function hook
86 */
87 function duplicateKiller_on_activate(){
88 duplicateKiller_create_table();
89 duplicateKiller_ensure_forms_duplicate_index();
90
91 $settings = get_option('DuplicateKillerSettings', []);
92 if (!is_array($settings)) {
93 $settings = array();
94 }
95
96 if (empty($settings['installed_at'])) {
97 $settings['installed_at'] = current_time('mysql');
98 }
99
100 $settings['plugin_version'] = DUPLICATEKILLER_VERSION;
101
102 update_option('DuplicateKillerSettings', $settings, false);
103 }
104 register_activation_hook( __FILE__, 'duplicateKiller_on_activate' );
105
106 function duplicateKiller_maybe_run_upgrade_tasks() {
107 if ( is_admin() ) {
108 $settings = get_option( 'DuplicateKillerSettings', array() );
109 if ( ! is_array( $settings ) ) {
110 $settings = array();
111 }
112
113 $stored_version = isset( $settings['plugin_version'] ) ? (string) $settings['plugin_version'] : '';
114
115 if ( $stored_version !== DUPLICATEKILLER_VERSION ) {
116 duplicateKiller_create_table();
117 duplicateKiller_ensure_forms_duplicate_index();
118
119 $settings['plugin_version'] = DUPLICATEKILLER_VERSION;
120 update_option( 'DuplicateKillerSettings', $settings, false );
121 }
122 }
123 }
124 add_action( 'admin_init', 'duplicateKiller_maybe_run_upgrade_tasks', 5 );
125
126 /**
127 * Ensure the main duplicate lookup index exists and has the expected structure.
128 *
129 * Safe to call multiple times.
130 *
131 * @return void
132 */
133 function duplicateKiller_ensure_forms_duplicate_index() {
134 global $wpdb;
135
136 $table_name = $wpdb->prefix . 'dk_forms_duplicate';
137 $index_name = 'dk_plugin_form_name_id';
138
139 // Check whether the plugin table exists before inspecting indexes.
140 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Schema inspection required for installation/upgrade routine.
141 $table_exists = $wpdb->get_var(
142 $wpdb->prepare(
143 'SHOW TABLES LIKE %s',
144 $table_name
145 )
146 );
147
148 if ( $table_exists !== $table_name ) {
149 return;
150 }
151
152 // Read the current index structure.
153 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Schema inspection required for installation/upgrade routine.
154 $indexes = $wpdb->get_results(
155 $wpdb->prepare(
156 "SELECT COLUMN_NAME
157 FROM INFORMATION_SCHEMA.STATISTICS
158 WHERE TABLE_SCHEMA = DATABASE()
159 AND TABLE_NAME = %s
160 AND INDEX_NAME = %s
161 ORDER BY SEQ_IN_INDEX ASC",
162 $table_name,
163 $index_name
164 ),
165 ARRAY_A
166 );
167
168 $expected_columns = array( 'form_plugin', 'form_name', 'form_id' );
169 $needs_rebuild = false;
170
171 if ( empty( $indexes ) ) {
172 $needs_rebuild = true;
173 } else {
174 $current_columns = array_column( $indexes, 'COLUMN_NAME' );
175
176 if ( $current_columns !== $expected_columns ) {
177 $needs_rebuild = true;
178 }
179 }
180
181 if ( ! $needs_rebuild ) {
182 return;
183 }
184
185 // Drop the existing index if it exists but has the wrong structure.
186 if ( ! empty( $indexes ) ) {
187 // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- DDL query required for installation/upgrade routine; table and index names are plugin-controlled.
188 $wpdb->query(
189 "ALTER TABLE `{$table_name}` DROP INDEX `{$index_name}`"
190 );
191 // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
192 }
193
194 // Create the expected composite index.
195 // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- DDL query required for installation/upgrade routine; table and index names are plugin-controlled.
196 $wpdb->query(
197 "ALTER TABLE `{$table_name}`
198 ADD INDEX `{$index_name}` (`form_plugin`, `form_name`, `form_id`)"
199 );
200 // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
201 }
202
203 //Fires when the upgrader process is complete
204 function duplicateKiller_upgrade_function( $upgrader_object, $options ) {
205 duplicateKiller_check_folder_and_database();
206 }
207 add_action( 'upgrader_process_complete', 'duplicateKiller_upgrade_function',10, 2);
208
209
210 /**
211 * Delete custom tables
212 */
213 register_uninstall_hook(
214 DUPLICATEKILLER_PLUGIN,
215 array('duplicateKiller_Deactivation_Feedback', 'uninstall')
216 );
217
218
219 /**
220 * Show settings link in wordpress installed plugins page
221 */
222 function duplicateKiller_settings_link($links) {
223 $forms_link = '<a href="'.admin_url('admin.php?page=duplicateKiller').'">'.esc_html__('Settings', 'duplicate-killer').'</a>';
224 array_unshift($links, $forms_link);
225 return $links;
226 }
227 $plugin = plugin_basename(__FILE__);
228 add_filter("plugin_action_links_$plugin", 'duplicateKiller_settings_link' );
229
230 /**
231 * Include plugin style
232 */
233 add_action( 'admin_enqueue_scripts', 'duplicateKiller_callback_for_setting_up_scripts' );
234
235 function duplicateKiller_callback_for_setting_up_scripts() {
236
237 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only admin routing param.
238 $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
239
240 // Only load assets on Duplicate Killer admin pages.
241 // Handles both: page=duplicateKiller and any subpages like page=duplicateKiller_something
242 if ( $page === '' || stripos( $page, 'duplicateKiller' ) !== 0 ) {
243 return;
244 }
245
246 wp_enqueue_style(
247 'duplicateKillerStyle',
248 plugins_url( 'assets/style.css', DUPLICATEKILLER_PLUGIN ),
249 array(),
250 DUPLICATEKILLER_VERSION
251 );
252
253 wp_enqueue_script( 'quicktags' );
254
255 wp_enqueue_script(
256 'duplicateKiller-admin',
257 plugins_url( 'assets/admin-settings.js', DUPLICATEKILLER_PLUGIN ),
258 array( 'quicktags' ),
259 DUPLICATEKILLER_VERSION,
260 true
261 );
262 }
263
264
265 /* Base Menu */
266 add_action('admin_menu', 'duplicateKiller_admin');
267 function duplicateKiller_admin(){
268 add_menu_page(
269 'DuplicateKiller', // the page title
270 'DuplicateKiller', // menu title
271 'manage_options', // capability
272 'duplicateKiller', // //menu slug/handle
273 'duplicateKiller_display_page', // callback function
274 'dashicons-images-alt2');
275 add_submenu_page(
276 'duplicateKiller',
277 'Submissions', //page title
278 'Submissions', //menu title
279 'manage_options', //capability,
280 'duplicateKiller_database',//menu slug
281 'duplicateKiller_database_display_page' //callback function
282 );
283 }
284 //add or update plugin settings
285 function duplicateKiller_update_settings($string,$value){
286 $options = get_option('DuplicateKillerSettings');
287 if($options){
288 $options[$string] = $value;
289 update_option("DuplicateKillerSettings",$options);
290 }else{
291 $options = [
292 $string => $value
293 ];
294 add_option("DuplicateKillerSettings",$options);
295 }
296 }
297 function duplicateKiller_get_setting($page,$string = ""){
298 if($page == "settings"){
299 $options = get_option('DuplicateKillerSettings');
300 if($options){
301 if(empty($string)){
302 return $options;
303 }else{
304 if(isset($options[$string])){
305 return $options[$string];
306 }
307
308 }
309 }
310 }elseif($page == "Forminator_page"){
311 $options = get_option('Forminator_page');
312 if($options){
313 if(empty($string)){
314 return $options;
315 }else{
316 if(isset($options[$string])){
317 return $options[$string];
318 }
319
320 }
321 }
322 }elseif($page == "CF7_page"){
323 $options = get_option('CF7_page');
324 if($options){
325 if(empty($string)){
326 return $options;
327 }else{
328 if(isset($options[$string])){
329 return $options[$string];
330 }
331
332 }
333 }
334 }elseif($page == "WPForms_page"){
335 $options = get_option('WPForms_page');
336 if($options){
337 if(empty($string)){
338 return $options;
339 }else{
340 if(isset($options[$string])){
341 return $options[$string];
342 }
343
344 }
345 }
346 }
347
348 return false;
349 }
350 function duplicateKiller_createUploadFolder() {
351 $upload_dir = wp_upload_dir();
352
353 // NEW (WP.org compliant): write only inside /uploads/duplicate-killer/
354 $dk_folder = trailingslashit( $upload_dir['basedir'] ) . 'duplicate-killer';
355
356 if ( ! file_exists( $dk_folder ) ) {
357 wp_mkdir_p( $dk_folder );
358 }
359
360 $index_file = trailingslashit( $dk_folder ) . 'index.php';
361
362 if ( ! file_exists( $index_file ) ) {
363 global $wp_filesystem;
364
365 if ( ! $wp_filesystem ) {
366 require_once ABSPATH . 'wp-admin/includes/file.php';
367 WP_Filesystem();
368 }
369
370 if ( $wp_filesystem ) {
371 $wp_filesystem->put_contents(
372 $index_file,
373 "<?php\n// Silence is golden.\n",
374 FS_CHMOD_FILE
375 );
376 }
377 }
378
379 // Backward compat:
380 // Older versions stored files in /uploads/dkcf7_uploads/.
381 // We do not write there anymore, but we keep it untouched so older files remain accessible.
382 }
383
384 function duplicateKiller_check_folder_and_database(){
385 $plugin_version = duplicateKiller_get_setting("settings","plugin_version");
386 if($plugin_version != DUPLICATEKILLER_VERSION){
387 duplicateKiller_update_settings("plugin_version",DUPLICATEKILLER_VERSION);
388 duplicateKiller_create_table();
389 duplicateKiller_createUploadFolder();
390 }
391 }
392 add_action('admin_init', 'duplicateKiller_options');
393 function duplicateKiller_options() {
394 duplicateKiller_check_folder_and_database();
395
396 $settings = array(
397 'CF7_page' => array(
398 'title' => 'Contact Form 7',
399 'description_cb' => 'duplicateKiller_CF7_description',
400 'validate_cb' => 'duplicateKiller_cf7_validate_input',
401 'fields' => array(
402 array('id' => 'CF7_forms', 'title' => '', 'callback' => 'duplicateKiller_cf7_select_form_tag_callback'),
403 array('id' => 'CF7_error_message', 'title' => '', 'callback' => 'duplicateKiller_cf7_settings_callback'),
404 ),
405 ),
406 'Forminator_page' => array(
407 'title' => 'Forminator',
408 'description_cb' => 'duplicateKiller_forminator_description',
409 'validate_cb' => 'duplicateKiller_forminator_validate_input',
410 'fields' => array(
411 array('id' => 'Forminator_forms', 'title' => '', 'callback' => 'duplicateKiller_forminator_select_form_tag_callback'),
412 array('id' => 'Forminator_error_message', 'title' => '', 'callback' => 'duplicateKiller_forminator_settings_callback'),
413 ),
414 ),
415 'WPForms_page' => array(
416 'title' => 'WPForms',
417 'description_cb' => 'duplicateKiller_WPForms_description',
418 'validate_cb' => 'duplicateKiller_wpforms_validate_input',
419 'fields' => array(
420 array('id' => 'WPForms_forms', 'title' => '', 'callback' => 'duplicateKiller_wpforms_select_form_tag_callback'),
421 array('id' => 'WPForms_error_message', 'title' => '', 'callback' => 'duplicateKiller_wpforms_settings_callback'),
422 ),
423 ),
424 'Breakdance_page' => array(
425 'title' => 'Breakdance',
426 'description_cb' => 'duplicateKiller_breakdance_description',
427 'validate_cb' => 'duplicateKiller_breakdance_validate_input',
428 'fields' => array(
429 array('id' => 'Breakdance_forms', 'title' => '', 'callback' => 'duplicateKiller_breakdance_select_form_tag_callback'),
430 array('id' => 'Breakdance_error_message', 'title' => '', 'callback' => 'duplicateKiller_breakdance_settings_callback'),
431 ),
432 ),
433 'Elementor_page' => array(
434 'title' => 'Elementor',
435 'description_cb' => 'duplicateKiller_elementor_description',
436 'validate_cb' => 'duplicateKiller_elementor_validate_input',
437 'fields' => array(
438 array('id' => 'Elementor_forms', 'title' => '', 'callback' => 'duplicateKiller_elementor_select_form_tag_callback'),
439 array('id' => 'Elementor_error_message', 'title' => '', 'callback' => 'duplicateKiller_elementor_settings_callback'),
440 ),
441 ),
442 'Formidable_page' => array(
443 'title' => 'Formidable',
444 'description_cb' => 'duplicateKiller_formidable_description',
445 'validate_cb' => 'duplicateKiller_formidable_validate_input',
446 'fields' => array(
447 array('id' => 'Formidable_forms', 'title' => '', 'callback' => 'duplicateKiller_formidable_select_form_tag_callback'),
448 array('id' => 'Formidable_error_message', 'title' => '', 'callback' => 'duplicateKiller_formidable_settings_callback'),
449 ),
450 ),
451 'NinjaForms_page' => array(
452 'title' => 'Formidable',
453 'description_cb' => 'duplicateKiller_ninjaforms_description',
454 'validate_cb' => 'duplicateKiller_ninjaforms_validate_input',
455 'fields' => array(
456 array('id' => 'NinjaForms_forms', 'title' => '', 'callback' => 'duplicateKiller_ninjaforms_select_form_tag_callback'),
457 array('id' => 'NinjaForms_error_message', 'title' => '', 'callback' => 'duplicateKiller_ninjaforms_settings_callback'),
458 ),
459 ),
460 'FluentForms_page' => array(
461 'title' => 'Fluent Forms',
462 'description_cb' => 'duplicateKiller_fluentforms_description',
463 'validate_cb' => 'duplicateKiller_fluentforms_validate_input',
464 'fields' => array(
465 array( 'id' => 'FluentForms_forms', 'title' => '', 'callback' => 'duplicateKiller_fluentforms_select_form_tag_callback' ),
466 array( 'id' => 'FluentForms_error_message', 'title' => '', 'callback' => 'duplicateKiller_fluentforms_settings_callback' ),
467 ),
468 ),
469 'WooCommerce_page' => array(
470 'title' => 'WooCommerce',
471 'description_cb' => array( 'duplicateKiller_WooCommerce', 'render_section' ),
472 'validate_cb' => '', // settings already registered by class; keep empty here
473 'fields' => array(
474 array('id' => 'dk_wc_settings', 'title' => '', 'callback' => array( 'duplicateKiller_WooCommerce', 'render_settings_field' )),
475 ),
476 ),
477 'Pro_page' => array(
478 'title' => 'Pro',
479 'description_cb' => 'duplicateKiller_pro_plugin',
480 'fields' => array(),
481 ),
482 );
483
484 foreach ($settings as $page => $data) {
485 add_settings_section(
486 $page . '_section',
487 '',
488 $data['description_cb'],
489 $page
490 );
491
492 foreach ($data['fields'] as $field) {
493 add_settings_field(
494 $field['id'],
495 $field['title'],
496 $field['callback'],
497 $page,
498 $page . '_section',
499 array($page, $field['title'])
500 );
501 }
502
503 // Înregistrăm doar dacă există funcție de validare
504 if (!empty($data['validate_cb'])) {
505 register_setting($page, $page, $data['validate_cb']);
506 }
507 }
508 }
509 /**
510 * Frontend footprint.
511 *
512 * Displays a small HTML comment in page source so developers
513 * can identify that Duplicate Killer is active.
514 */
515 add_action( 'wp_footer', 'duplicateKiller_frontend_powered_by_comment', 999 );
516
517 function duplicateKiller_frontend_powered_by_comment() {
518
519 if ( is_admin() ) {
520 return;
521 }
522
523 echo "\n<!-- Duplicate protection powered by Duplicate Killer by VerseLabWP -->\n";
524 }
525 /**
526 * Display Page
527 */
528
529 function duplicateKiller_do_settings_sections( $page ) {
530 global $wp_settings_sections, $wp_settings_fields;
531
532 if ( ! isset( $wp_settings_sections[ $page ] ) ) {
533 return;
534 }
535
536 foreach ( (array) $wp_settings_sections[ $page ] as $section ) {
537 if ( ! empty( $section['title'] ) ) {
538 echo '<h3>' . esc_html( $section['title'] ) . "</h3>\n";
539 }
540
541 if ( $section['callback'] ) {
542 call_user_func( $section['callback'], $section );
543 }
544
545 if ( ! isset( $wp_settings_fields ) ||
546 ! isset( $wp_settings_fields[ $page ] ) ||
547 ! isset( $wp_settings_fields[ $page ][ $section['id'] ] )
548 ) {
549 continue;
550 }
551 echo '<div class="settings-form-wrapper">';
552 duplicateKiller_do_settings_fields( $page, $section['id'] );
553 echo '</div>';
554 }
555 }
556
557 function duplicateKiller_do_settings_fields( $page, $section ) {
558 global $wp_settings_fields;
559
560 if ( ! isset( $wp_settings_fields[ $page ][ $section ] ) ) {
561 return;
562 }
563
564 foreach ( (array) $wp_settings_fields[ $page ][ $section ] as $field ) {
565 echo '<div class="dk-settings-form-row flex-tab">';
566
567 echo '<p>';
568 if ( ! empty( $field['args']['label_for'] ) ) {
569 echo '<label for="' . esc_attr( $field['args']['label_for'] ) . '">' . esc_attr($field['title']) . '</label>';
570 } else {
571 echo esc_attr($field['title']);
572 }
573
574 call_user_func( $field['callback'], $field['args'] );
575 echo '</p>';
576
577 echo '</div>';
578 }
579 }
580 function duplicateKiller_display_page() {
581 ?>
582 <div class="wrap">
583 <h2><?php esc_html_e('DuplicateKiller','duplicate-killer');?></h2>
584 <?php settings_errors();
585 $allowed_tabs = array(
586 'first',
587 'second',
588 'third',
589 'fourth',
590 'fifth',
591 'sixth',
592 'seventh',
593 'fluentforms',
594 'woocommerce',
595 'pro',
596 'support',
597 );
598
599 $active_tab = 'first';
600 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading a UI navigation param (non-destructive).
601 if ( isset( $_GET['tab'] ) ) {
602 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reading a UI navigation param (non-destructive).
603 $tab = sanitize_key( wp_unslash( $_GET['tab'] ) );
604
605 if ( in_array( $tab, $allowed_tabs, true ) ) {
606 $active_tab = $tab;
607 }
608 }
609 ?>
610 <h2 class="nav-tab-wrapper">
611 <a href="?page=duplicateKiller&tab=first" class="nav-tab <?php echo esc_attr($active_tab == 'first' ? 'nav-tab-active' : ''); ?>"><?php esc_html_e('Contact Form 7','duplicate-killer');?>
612 </a>
613 <a href="?page=duplicateKiller&tab=second" class="nav-tab <?php echo esc_attr($active_tab == 'second' ? 'nav-tab-active' : ''); ?>"><?php esc_html_e('Forminator','duplicate-killer');?>
614 </a>
615 <a href="?page=duplicateKiller&tab=third" class="nav-tab <?php echo esc_attr($active_tab == 'third' ? 'nav-tab-active' : ''); ?>"><?php esc_html_e('WPForms Free','duplicate-killer');?></a>
616 <a href="?page=duplicateKiller&tab=fourth" class="nav-tab <?php echo esc_attr($active_tab == 'fourth' ? 'nav-tab-active' : ''); ?>"><?php esc_html_e('Breakdance','duplicate-killer');?></a>
617 <a href="?page=duplicateKiller&tab=fifth" class="nav-tab <?php echo esc_attr($active_tab == 'fifth' ? 'nav-tab-active' : ''); ?>"><?php esc_html_e('Elementor','duplicate-killer');?></a>
618
619 <a href="?page=duplicateKiller&tab=sixth" class="nav-tab <?php echo esc_attr($active_tab == 'sixth' ? 'nav-tab-active' : ''); ?>"><?php esc_html_e('Formidable','duplicate-killer');?></a>
620
621 <a href="?page=duplicateKiller&tab=seventh" class="nav-tab <?php echo esc_attr($active_tab == 'seventh' ? 'nav-tab-active' : ''); ?>"><?php esc_html_e('Ninja Forms','duplicate-killer');?></a>
622
623 <a href="?page=duplicateKiller&tab=fluentforms" class="nav-tab dk-nav-tab-new <?php echo esc_attr( $active_tab === 'fluentforms' ? 'nav-tab-active' : '' ); ?>">
624 <?php esc_html_e( 'Fluent Forms', 'duplicate-killer' ); ?>
625 <span class="dk-new-badge"><?php esc_html_e( 'New', 'duplicate-killer' ); ?></span>
626 </a>
627
628 <a href="?page=duplicateKiller&tab=woocommerce" class="nav-tab <?php echo esc_attr($active_tab == 'woocommerce' ? 'nav-tab-active' : ''); ?>">
629 <?php esc_html_e('WooCommerce','duplicate-killer'); ?>
630 </a>
631 <a href="?page=duplicateKiller&tab=pro"
632 class="nav-tab dk-pro-tab <?php echo esc_attr($active_tab == 'pro' ? 'nav-tab-active' : ''); ?>">
633 <?php esc_html_e('PRO','duplicate-killer');?>
634 </a>
635 <a href="<?php echo esc_url( admin_url('admin.php?page=duplicateKiller_diagnostics') ); ?>" class="nav-tab dk-nav-tab-diagnostics">
636 <?php esc_html_e('Diagnostics','duplicate-killer'); ?>
637 </a>
638 </h2>
639 <form method="post" action="options.php">
640 <?php
641 wp_nonce_field('dk_delete_logs', 'dk_nonce' );
642 if($active_tab == 'first') {
643 settings_fields('CF7_page');
644 duplicateKiller_do_settings_sections('CF7_page');
645 submit_button();
646 }elseif($active_tab == 'second') {
647 settings_fields('Forminator_page');
648 duplicateKiller_do_settings_sections('Forminator_page');
649 submit_button();
650 }elseif($active_tab == 'third') {
651 settings_fields('WPForms_page');
652 duplicateKiller_do_settings_sections('WPForms_page');
653 submit_button();
654 }elseif($active_tab == 'fourth') {
655 settings_fields('Breakdance_page');
656 duplicateKiller_do_settings_sections('Breakdance_page');
657 submit_button();
658 }elseif($active_tab == 'fifth') {
659 settings_fields('Elementor_page');
660 duplicateKiller_do_settings_sections('Elementor_page');
661 submit_button();
662 }elseif($active_tab == 'sixth') {
663 settings_fields('Formidable_page');
664 duplicateKiller_do_settings_sections('Formidable_page');
665 submit_button();
666 }elseif($active_tab == 'seventh') {
667 settings_fields('NinjaForms_page');
668 duplicateKiller_do_settings_sections('NinjaForms_page');
669 submit_button();
670 }elseif ( $active_tab === 'fluentforms' ) {
671 settings_fields( 'FluentForms_page' );
672 duplicateKiller_do_settings_sections( 'FluentForms_page' );
673 submit_button();
674 }elseif($active_tab == 'woocommerce') {
675 settings_fields('WooCommerce_page');
676 duplicateKiller_do_settings_sections('WooCommerce_page');
677 submit_button();
678 }elseif($active_tab == 'pro') {
679 settings_fields('Pro_page');
680 duplicateKiller_do_settings_sections('Pro_page');
681 }
682 ?>
683 </form>
684 </div>
685 <?php
686 }