prefix.'dk_forms_duplicate'; $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE $table_name ( form_id bigint(20) NOT NULL AUTO_INCREMENT, form_plugin varchar(50) NOT NULL, form_name varchar(50) NOT NULL, form_value longtext NOT NULL, form_cookie longtext NOT NULL, form_ip varchar(50) NOT NULL, form_date datetime NOT NULL, PRIMARY KEY (form_id) ) $charset_collate;"; require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); dbDelta( $sql ); } /** * Activation function hook */ function duplicateKiller_on_activate(){ duplicateKiller_create_table(); duplicateKiller_ensure_forms_duplicate_index(); $settings = get_option('DuplicateKillerSettings', []); if (!is_array($settings)) { $settings = array(); } if (empty($settings['installed_at'])) { $settings['installed_at'] = current_time('mysql'); } $settings['plugin_version'] = DUPLICATEKILLER_VERSION; update_option('DuplicateKillerSettings', $settings, false); } register_activation_hook( __FILE__, 'duplicateKiller_on_activate' ); function duplicateKiller_maybe_run_upgrade_tasks() { if ( is_admin() ) { $settings = get_option( 'DuplicateKillerSettings', array() ); if ( ! is_array( $settings ) ) { $settings = array(); } $stored_version = isset( $settings['plugin_version'] ) ? (string) $settings['plugin_version'] : ''; if ( $stored_version !== DUPLICATEKILLER_VERSION ) { duplicateKiller_create_table(); duplicateKiller_ensure_forms_duplicate_index(); $settings['plugin_version'] = DUPLICATEKILLER_VERSION; update_option( 'DuplicateKillerSettings', $settings, false ); } } } add_action( 'admin_init', 'duplicateKiller_maybe_run_upgrade_tasks', 5 ); /** * Ensure the main duplicate lookup index exists and has the expected structure. * * Safe to call multiple times. * * @return void */ function duplicateKiller_ensure_forms_duplicate_index() { global $wpdb; $table_name = $wpdb->prefix . 'dk_forms_duplicate'; $index_name = 'dk_plugin_form_name_id'; // Check whether the plugin table exists before inspecting indexes. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Schema inspection required for installation/upgrade routine. $table_exists = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name ) ); if ( $table_exists !== $table_name ) { return; } // Read the current index structure. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Schema inspection required for installation/upgrade routine. $indexes = $wpdb->get_results( $wpdb->prepare( "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = %s AND INDEX_NAME = %s ORDER BY SEQ_IN_INDEX ASC", $table_name, $index_name ), ARRAY_A ); $expected_columns = array( 'form_plugin', 'form_name', 'form_id' ); $needs_rebuild = false; if ( empty( $indexes ) ) { $needs_rebuild = true; } else { $current_columns = array_column( $indexes, 'COLUMN_NAME' ); if ( $current_columns !== $expected_columns ) { $needs_rebuild = true; } } if ( ! $needs_rebuild ) { return; } // Drop the existing index if it exists but has the wrong structure. if ( ! empty( $indexes ) ) { // 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. $wpdb->query( "ALTER TABLE `{$table_name}` DROP INDEX `{$index_name}`" ); // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter } // Create the expected composite index. // 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. $wpdb->query( "ALTER TABLE `{$table_name}` ADD INDEX `{$index_name}` (`form_plugin`, `form_name`, `form_id`)" ); // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter } //Fires when the upgrader process is complete function duplicateKiller_upgrade_function( $upgrader_object, $options ) { duplicateKiller_check_folder_and_database(); } add_action( 'upgrader_process_complete', 'duplicateKiller_upgrade_function',10, 2); /** * Delete custom tables */ register_uninstall_hook( DUPLICATEKILLER_PLUGIN, array('duplicateKiller_Deactivation_Feedback', 'uninstall') ); /** * Show settings link in wordpress installed plugins page */ function duplicateKiller_settings_link($links) { $forms_link = ''.esc_html__('Settings', 'duplicate-killer').''; array_unshift($links, $forms_link); return $links; } $plugin = plugin_basename(__FILE__); add_filter("plugin_action_links_$plugin", 'duplicateKiller_settings_link' ); /** * Include plugin style */ add_action( 'admin_enqueue_scripts', 'duplicateKiller_callback_for_setting_up_scripts' ); function duplicateKiller_callback_for_setting_up_scripts() { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only admin routing param. $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; // Only load assets on Duplicate Killer admin pages. // Handles both: page=duplicateKiller and any subpages like page=duplicateKiller_something if ( $page === '' || stripos( $page, 'duplicateKiller' ) !== 0 ) { return; } wp_enqueue_style( 'duplicateKillerStyle', plugins_url( 'assets/style.css', DUPLICATEKILLER_PLUGIN ), array(), DUPLICATEKILLER_VERSION ); wp_enqueue_script( 'quicktags' ); wp_enqueue_script( 'duplicateKiller-admin', plugins_url( 'assets/admin-settings.js', DUPLICATEKILLER_PLUGIN ), array( 'quicktags' ), DUPLICATEKILLER_VERSION, true ); } /* Base Menu */ add_action('admin_menu', 'duplicateKiller_admin'); function duplicateKiller_admin(){ add_menu_page( 'DuplicateKiller', // the page title 'DuplicateKiller', // menu title 'manage_options', // capability 'duplicateKiller', // //menu slug/handle 'duplicateKiller_display_page', // callback function 'dashicons-images-alt2'); add_submenu_page( 'duplicateKiller', 'Submissions', //page title 'Submissions', //menu title 'manage_options', //capability, 'duplicateKiller_database',//menu slug 'duplicateKiller_database_display_page' //callback function ); } //add or update plugin settings function duplicateKiller_update_settings($string,$value){ $options = get_option('DuplicateKillerSettings'); if($options){ $options[$string] = $value; update_option("DuplicateKillerSettings",$options); }else{ $options = [ $string => $value ]; add_option("DuplicateKillerSettings",$options); } } function duplicateKiller_get_setting($page,$string = ""){ if($page == "settings"){ $options = get_option('DuplicateKillerSettings'); if($options){ if(empty($string)){ return $options; }else{ if(isset($options[$string])){ return $options[$string]; } } } }elseif($page == "Forminator_page"){ $options = get_option('Forminator_page'); if($options){ if(empty($string)){ return $options; }else{ if(isset($options[$string])){ return $options[$string]; } } } }elseif($page == "CF7_page"){ $options = get_option('CF7_page'); if($options){ if(empty($string)){ return $options; }else{ if(isset($options[$string])){ return $options[$string]; } } } }elseif($page == "WPForms_page"){ $options = get_option('WPForms_page'); if($options){ if(empty($string)){ return $options; }else{ if(isset($options[$string])){ return $options[$string]; } } } } return false; } function duplicateKiller_createUploadFolder() { $upload_dir = wp_upload_dir(); // NEW (WP.org compliant): write only inside /uploads/duplicate-killer/ $dk_folder = trailingslashit( $upload_dir['basedir'] ) . 'duplicate-killer'; if ( ! file_exists( $dk_folder ) ) { wp_mkdir_p( $dk_folder ); } $index_file = trailingslashit( $dk_folder ) . 'index.php'; if ( ! file_exists( $index_file ) ) { global $wp_filesystem; if ( ! $wp_filesystem ) { require_once ABSPATH . 'wp-admin/includes/file.php'; WP_Filesystem(); } if ( $wp_filesystem ) { $wp_filesystem->put_contents( $index_file, " array( 'title' => 'Contact Form 7', 'description_cb' => 'duplicateKiller_CF7_description', 'validate_cb' => 'duplicateKiller_cf7_validate_input', 'fields' => array( array('id' => 'CF7_forms', 'title' => '', 'callback' => 'duplicateKiller_cf7_select_form_tag_callback'), array('id' => 'CF7_error_message', 'title' => '', 'callback' => 'duplicateKiller_cf7_settings_callback'), ), ), 'Forminator_page' => array( 'title' => 'Forminator', 'description_cb' => 'duplicateKiller_forminator_description', 'validate_cb' => 'duplicateKiller_forminator_validate_input', 'fields' => array( array('id' => 'Forminator_forms', 'title' => '', 'callback' => 'duplicateKiller_forminator_select_form_tag_callback'), array('id' => 'Forminator_error_message', 'title' => '', 'callback' => 'duplicateKiller_forminator_settings_callback'), ), ), 'WPForms_page' => array( 'title' => 'WPForms', 'description_cb' => 'duplicateKiller_WPForms_description', 'validate_cb' => 'duplicateKiller_wpforms_validate_input', 'fields' => array( array('id' => 'WPForms_forms', 'title' => '', 'callback' => 'duplicateKiller_wpforms_select_form_tag_callback'), array('id' => 'WPForms_error_message', 'title' => '', 'callback' => 'duplicateKiller_wpforms_settings_callback'), ), ), 'Breakdance_page' => array( 'title' => 'Breakdance', 'description_cb' => 'duplicateKiller_breakdance_description', 'validate_cb' => 'duplicateKiller_breakdance_validate_input', 'fields' => array( array('id' => 'Breakdance_forms', 'title' => '', 'callback' => 'duplicateKiller_breakdance_select_form_tag_callback'), array('id' => 'Breakdance_error_message', 'title' => '', 'callback' => 'duplicateKiller_breakdance_settings_callback'), ), ), 'Elementor_page' => array( 'title' => 'Elementor', 'description_cb' => 'duplicateKiller_elementor_description', 'validate_cb' => 'duplicateKiller_elementor_validate_input', 'fields' => array( array('id' => 'Elementor_forms', 'title' => '', 'callback' => 'duplicateKiller_elementor_select_form_tag_callback'), array('id' => 'Elementor_error_message', 'title' => '', 'callback' => 'duplicateKiller_elementor_settings_callback'), ), ), 'Formidable_page' => array( 'title' => 'Formidable', 'description_cb' => 'duplicateKiller_formidable_description', 'validate_cb' => 'duplicateKiller_formidable_validate_input', 'fields' => array( array('id' => 'Formidable_forms', 'title' => '', 'callback' => 'duplicateKiller_formidable_select_form_tag_callback'), array('id' => 'Formidable_error_message', 'title' => '', 'callback' => 'duplicateKiller_formidable_settings_callback'), ), ), 'NinjaForms_page' => array( 'title' => 'Formidable', 'description_cb' => 'duplicateKiller_ninjaforms_description', 'validate_cb' => 'duplicateKiller_ninjaforms_validate_input', 'fields' => array( array('id' => 'NinjaForms_forms', 'title' => '', 'callback' => 'duplicateKiller_ninjaforms_select_form_tag_callback'), array('id' => 'NinjaForms_error_message', 'title' => '', 'callback' => 'duplicateKiller_ninjaforms_settings_callback'), ), ), 'FluentForms_page' => array( 'title' => 'Fluent Forms', 'description_cb' => 'duplicateKiller_fluentforms_description', 'validate_cb' => 'duplicateKiller_fluentforms_validate_input', 'fields' => array( array( 'id' => 'FluentForms_forms', 'title' => '', 'callback' => 'duplicateKiller_fluentforms_select_form_tag_callback' ), array( 'id' => 'FluentForms_error_message', 'title' => '', 'callback' => 'duplicateKiller_fluentforms_settings_callback' ), ), ), 'WooCommerce_page' => array( 'title' => 'WooCommerce', 'description_cb' => array( 'duplicateKiller_WooCommerce', 'render_section' ), 'validate_cb' => '', // settings already registered by class; keep empty here 'fields' => array( array('id' => 'dk_wc_settings', 'title' => '', 'callback' => array( 'duplicateKiller_WooCommerce', 'render_settings_field' )), ), ), 'Pro_page' => array( 'title' => 'Pro', 'description_cb' => 'duplicateKiller_pro_plugin', 'fields' => array(), ), ); foreach ($settings as $page => $data) { add_settings_section( $page . '_section', '', $data['description_cb'], $page ); foreach ($data['fields'] as $field) { add_settings_field( $field['id'], $field['title'], $field['callback'], $page, $page . '_section', array($page, $field['title']) ); } // Înregistrăm doar dacă există funcție de validare if (!empty($data['validate_cb'])) { register_setting($page, $page, $data['validate_cb']); } } } /** * Frontend footprint. * * Displays a small HTML comment in page source so developers * can identify that Duplicate Killer is active. */ add_action( 'wp_footer', 'duplicateKiller_frontend_powered_by_comment', 999 ); function duplicateKiller_frontend_powered_by_comment() { if ( is_admin() ) { return; } echo "\n\n"; } /** * Display Page */ function duplicateKiller_do_settings_sections( $page ) { global $wp_settings_sections, $wp_settings_fields; if ( ! isset( $wp_settings_sections[ $page ] ) ) { return; } foreach ( (array) $wp_settings_sections[ $page ] as $section ) { if ( ! empty( $section['title'] ) ) { echo '

' . esc_html( $section['title'] ) . "

\n"; } if ( $section['callback'] ) { call_user_func( $section['callback'], $section ); } if ( ! isset( $wp_settings_fields ) || ! isset( $wp_settings_fields[ $page ] ) || ! isset( $wp_settings_fields[ $page ][ $section['id'] ] ) ) { continue; } echo '
'; duplicateKiller_do_settings_fields( $page, $section['id'] ); echo '
'; } } function duplicateKiller_do_settings_fields( $page, $section ) { global $wp_settings_fields; if ( ! isset( $wp_settings_fields[ $page ][ $section ] ) ) { return; } foreach ( (array) $wp_settings_fields[ $page ][ $section ] as $field ) { echo '
'; echo '

'; if ( ! empty( $field['args']['label_for'] ) ) { echo ''; } else { echo esc_attr($field['title']); } call_user_func( $field['callback'], $field['args'] ); echo '

'; echo '
'; } } function duplicateKiller_display_page() { ?>