From 633fd2995972a4224731f9da2d393a8b8ac15a08 Mon Sep 17 00:00:00 2001 From: Guilherme Branco Stracini Date: Fri, 22 May 2026 11:49:14 +0100 Subject: [PATCH 1/7] docs: rename plugin to comply with WordPress.org Rename the plugin from "IpQuery" to "Stracini Visitor Analytics with IpQuery" following trademark compliance requirements from the WordPress.org Plugin Review Team. The plugin needed a clear distinction as a third-party integration with IpQuery. - Updated plugin name in README.md and documentation files. - Adjusted dashboard and settings navigation labels for clearer identification. - Added a notice in the README.md explaining the renaming and mentioning the unchanged internal components like class names and database tables. --- README.md | 11 ++++++++--- docs/_config.yml | 7 ++++--- docs/configuration.md | 2 +- docs/dashboard.md | 2 +- docs/index.md | 2 +- docs/installation.md | 4 ++-- docs/privacy.md | 4 ++-- docs/visitors.md | 4 ++-- 8 files changed, 21 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index e707937..649a4d6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@
-# 🌍 IpQuery +# 🌍 Stracini Visitor Analytics with IpQuery **Track and analyse every visitor. Visualise traffic. Detect threats.** @@ -16,6 +16,11 @@ A WordPress plugin that enriches visitor IP addresses with real-time geolocation
+> **Plugin renamed for WordPress.org directory compliance** +> The WordPress.org Plugin Review Team flagged "IpQuery" as a trademark that belongs to the [IpQuery API](https://ipquery.io) service. +> The plugin has been renamed to **Stracini Visitor Analytics with IpQuery** to make it clear this is an independent, third-party integration and is not officially affiliated with IpQuery. +> The repository name, internal class names, database table, and option keys are unchanged. + --- ## ✨ Features @@ -40,7 +45,7 @@ A WordPress plugin that enriches visitor IP addresses with real-time geolocation ### Dashboard -The plugin adds an **IpQuery** entry to the WordPress admin sidebar with three sub-pages. +The plugin adds a **Visitor Analytics** entry to the WordPress admin sidebar with three sub-pages. **Dashboard** — a live overview built from four widgets: @@ -136,7 +141,7 @@ The plugin automatically: ## ⚙️ Configuration -Navigate to **IpQuery → Settings** to configure: +Navigate to **Visitor Analytics → Settings** to configure: | Setting | Default | Description | |---|---|---| diff --git a/docs/_config.yml b/docs/_config.yml index 969d27c..33f4386 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,13 +1,14 @@ # ====================================================================== -# IpQuery Wordpress Plugin documentation site — Jekyll + just-the-docs +# Stracini Visitor Analytics with IpQuery — Jekyll + just-the-docs # Lives at: /docs (in the ipquery-wordpress repo) # Serves from: https://guilherme.stracini.com.br/ipquery-wordpress/ # ====================================================================== -title: IpQuery +title: Stracini Visitor Analytics with IpQuery description: >- Track and analyse visitor IP data using the IpQuery API. Displays location maps, traffic heatmaps, and VPN/proxy statistics. + This plugin is not officially affiliated with IpQuery. remote_theme: just-the-docs/just-the-docs@v0.12.0 url: https://guilherme.stracini.com.br @@ -70,7 +71,7 @@ enable_copy_code_button: true # ---------------------------------------------------------------------- footer_content: >- © 2026 Guilherme Branco Stracini. - IpQuery is open source under the + Stracini Visitor Analytics with IpQuery is open source under the MIT license. Built with Just the Docs. Powered by guibranco/ipquery-php diff --git a/docs/configuration.md b/docs/configuration.md index 7854222..02c813f 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -5,7 +5,7 @@ nav_order: 3 # Configuration -All settings are found at **IpQuery → Settings** in the WordPress admin. +All settings are found at **Visitor Analytics → Settings** in the WordPress admin. --- diff --git a/docs/dashboard.md b/docs/dashboard.md index 896bce6..bb91699 100644 --- a/docs/dashboard.md +++ b/docs/dashboard.md @@ -5,7 +5,7 @@ nav_order: 4 # Dashboard -The dashboard is at **IpQuery → Dashboard**. It gives a live overview of all tracked visitor data. +The dashboard is at **Visitor Analytics → Dashboard**. It gives a live overview of all tracked visitor data. --- diff --git a/docs/index.md b/docs/index.md index 243a467..b2b50a2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -4,7 +4,7 @@ nav_order: 1 permalink: / --- -# IpQuery for WordPress +# Stracini Visitor Analytics with IpQuery Track and analyse visitor IP data directly from your WordPress admin panel — see where your visitors come from on an interactive heatmap, identify VPN and proxy traffic, and drill into per-IP details. diff --git a/docs/installation.md b/docs/installation.md index 9d9ca21..b039cb2 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -35,7 +35,7 @@ No Composer or external package manager is needed. The [ipquery-php](https://git git clone https://github.com/guibranco/ipquery-wordpress.git ``` 2. Copy the `ipquery-wordpress` folder into your `wp-content/plugins/` directory. -3. In your WordPress admin, go to **Plugins** and activate **IpQuery**. +3. In your WordPress admin, go to **Plugins** and activate **Stracini Visitor Analytics with IpQuery**. --- @@ -65,6 +65,6 @@ Uninstalling the plugin permanently deletes all collected visitor data. ## After activation -Once active, the plugin immediately starts tracking visitors (based on your [settings]({% link configuration.md %})). Navigate to **IpQuery → Dashboard** in the WordPress admin sidebar to see the interface. +Once active, the plugin immediately starts tracking visitors (based on your [settings]({% link configuration.md %})). Navigate to **Visitor Analytics → Dashboard** in the WordPress admin sidebar to see the interface. [Configure the plugin →]({% link configuration.md %}){: .btn .btn-primary } diff --git a/docs/privacy.md b/docs/privacy.md index 3b6aec8..3eed243 100644 --- a/docs/privacy.md +++ b/docs/privacy.md @@ -71,7 +71,7 @@ All collected data is stored in the `wp_ipquery_visitors` table in your own Word If you use this plugin, consider adding a clause similar to the following to your privacy policy: -> We use the IpQuery for WordPress plugin to analyse visitor traffic. Your IP address is sent to the IpQuery API (ipquery.io) to retrieve geolocation and network risk information. This information is stored in our database for up to [X] days and is used solely for security and analytics purposes. It is not shared with third parties. You may request deletion of your data by contacting us at [your contact address]. +> We use the Stracini Visitor Analytics with IpQuery plugin to analyse visitor traffic. Your IP address is sent to the IpQuery API (ipquery.io) to retrieve geolocation and network risk information. This information is stored in our database for up to [X] days and is used solely for security and analytics purposes. It is not shared with third parties. You may request deletion of your data by contacting us at [your contact address]. --- @@ -84,7 +84,7 @@ Key properties of the tool: - **Targeted** — selects records by the `country_code` field stored from the IpQuery API response; only countries with stored records are shown. - **Bulk** — a single operation removes all matching records across as many countries as you select. - **Safe** — a mandatory confirmation dialog shows the affected countries and record count before any data is deleted. -- **Auditable** — every deletion is written to the plugin action log (`IpQuery → Logs`) with the operator identity, country list, record count, and UTC timestamp. +- **Auditable** — every deletion is written to the plugin action log (`Visitor Analytics → Logs`) with the operator identity, country list, record count, and UTC timestamp. See [Deleting records by country]({% link visitors.md %}#deleting-records-by-country) for step-by-step instructions. diff --git a/docs/visitors.md b/docs/visitors.md index f1270ec..c6165fb 100644 --- a/docs/visitors.md +++ b/docs/visitors.md @@ -5,7 +5,7 @@ nav_order: 5 # Visitors -The Visitors screen is at **IpQuery → Visitors**. It shows every IP address in the database with its full enrichment data, and provides tools for searching, filtering, manual lookups, and data purging. +The Visitors screen is at **Visitor Analytics → Visitors**. It shows every IP address in the database with its full enrichment data, and provides tools for searching, filtering, manual lookups, and data purging. --- @@ -134,7 +134,7 @@ Every country-filter deletion is written to the plugin's action log with: | **Performed by** | WordPress user ID and display name | | **Timestamp** | UTC date and time of the operation | -The log is accessible under **IpQuery → Logs** and is retained for 90 days. +The log is accessible under **Visitor Analytics → Logs** and is retained for 90 days. {: .warning } Country-filter deletion is irreversible. All records for the selected countries are permanently removed and cannot be recovered. From aad645f1c756b84683c2727cbfc227987196775d Mon Sep 17 00:00:00 2001 From: Guilherme Branco Stracini Date: Fri, 22 May 2026 11:53:48 +0100 Subject: [PATCH 2/7] chore: update readme for compatibility and version bump Update the 'Tested up to' WordPress version to 7.0 to reflect compatibility with the latest release. Bump the stable tag from 1.2.0 to 1.3.0 to denote that the plugin has been updated and tested with the new WordPress version. These changes ensure users are informed about the plugin's current compatibility and stability status. --- readme.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.txt b/readme.txt index 6187223..e2ea6d1 100644 --- a/readme.txt +++ b/readme.txt @@ -2,9 +2,9 @@ Contributors: guilhermestracini Tags: ip, geolocation, analytics, security, heatmap Requires at least: 6.0 -Tested up to: 6.9 +Tested up to: 7.0 Requires PHP: 8.2 -Stable tag: 1.2.0 +Stable tag: 1.3.0 License: MIT License URI: https://opensource.org/licenses/MIT From 573828e0e7a71331c41d293c912d16f003be0da9 Mon Sep 17 00:00:00 2001 From: Guilherme Branco Stracini Date: Sat, 23 May 2026 11:01:14 +0100 Subject: [PATCH 3/7] plaintext docs: update plugin name and data storage details Update the plugin name from "IpQuery" to "Stracini Visitor Analytics with IpQuery" for consistency with branding. Modify the description to include the full plugin name instead of just "IpQuery". Change the database storage table reference from `wp_ipquery_visitors` to `wp_stracini_visitor_analytics_visitors` to reflect the updated plugin name. These changes improve the clarity and coherence of the documentation. --- readme.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.txt b/readme.txt index e2ea6d1..be315af 100644 --- a/readme.txt +++ b/readme.txt @@ -8,11 +8,11 @@ Stable tag: 1.3.0 License: MIT License URI: https://opensource.org/licenses/MIT -Track and analyse visitor IP data using the IpQuery API. Displays location maps, traffic heatmaps, and VPN/proxy/Tor statistics. This plugin is not officially affiliated with IpQuery. +Track and analyze visitor IP data using the IpQuery API. Displays location maps, traffic heatmaps, and VPN/proxy/Tor statistics. This plugin is not officially affiliated with IpQuery. == Description == -IpQuery enriches every visitor's IP address with real-time geolocation, ISP data, and risk intelligence — powered by the [IpQuery API](https://ipquery.io) via the bundled [guibranco/ipquery-php](https://github.com/guibranco/ipquery-php) library. +Stracini Visitor Analytics with IpQuery enriches every visitor's IP address with real-time geolocation, ISP data, and risk intelligence — powered by the [IpQuery API](https://ipquery.io) via the bundled [guibranco/ipquery-php](https://github.com/guibranco/ipquery-php) library. **Features:** @@ -60,7 +60,7 @@ Navigate to **IpQuery → Settings → GDPR Erasure**, select the country from t = Where is data stored? = -All data is stored in your own WordPress database in the `wp_ipquery_visitors` table. No data is sent to any service other than the IpQuery API lookup. +All data is stored in your own WordPress database in the `wp_stracini_visitor_analytics_visitors` table. No data is sent to any service other than the IpQuery API lookup. == Screenshots == From c7d4cd86e40d86bcaf18602593f1d0c6768ae2ec Mon Sep 17 00:00:00 2001 From: Guilherme Branco Stracini Date: Sat, 23 May 2026 12:58:31 +0100 Subject: [PATCH 4/7] refactor: rename plugin classes and constants from IpQuery to SVA Rename all class, file, and variable references from IpQuery to SVA to better reflect the Stracini Visitor Analytics branding. This includes renaming database tables, AJAX actions, and other identifiers. These changes ensure consistent naming following the rebranding, and maintain compatibility across references in code and configurations. --- ...-ipquery-admin.php => class-sva-admin.php} | 130 +++++++++--------- ...{class-ipquery-db.php => class-sva-db.php} | 44 +++--- ...uery-tracker.php => class-sva-tracker.php} | 12 +- ipquery.php | 71 ---------- stracini-visitor-analytics.php | 71 ++++++++++ tests/bootstrap.php | 30 ++-- tests/unit/DbTest.php | 12 +- tests/unit/TrackerTest.php | 38 ++--- 8 files changed, 204 insertions(+), 204 deletions(-) rename includes/{class-ipquery-admin.php => class-sva-admin.php} (72%) rename includes/{class-ipquery-db.php => class-sva-db.php} (94%) rename includes/{class-ipquery-tracker.php => class-sva-tracker.php} (94%) delete mode 100644 ipquery.php create mode 100644 stracini-visitor-analytics.php diff --git a/includes/class-ipquery-admin.php b/includes/class-sva-admin.php similarity index 72% rename from includes/class-ipquery-admin.php rename to includes/class-sva-admin.php index cee9463..c20e26e 100644 --- a/includes/class-ipquery-admin.php +++ b/includes/class-sva-admin.php @@ -2,7 +2,7 @@ /** * Admin controller — menus, asset enqueueing, form handlers, and AJAX endpoints. * - * @package IpQuery + * @package SVA */ defined( 'ABSPATH' ) || exit; @@ -13,7 +13,7 @@ /** * Registers and handles all WordPress admin functionality for IpQuery. */ -class IpQuery_Admin { +class SVA_Admin { /** * Registers all admin hooks. @@ -24,19 +24,19 @@ public static function init(): void { add_action( 'admin_menu', array( self::class, 'register_menu' ) ); add_action( 'admin_enqueue_scripts', array( self::class, 'enqueue_assets' ) ); add_action( 'admin_init', array( self::class, 'handle_settings_save' ) ); - add_action( 'admin_post_ipquery_delete_ip', array( self::class, 'handle_delete_ip' ) ); - add_action( 'admin_post_ipquery_delete_by_country', array( self::class, 'handle_delete_by_country' ) ); - add_action( 'admin_post_ipquery_purge', array( self::class, 'handle_purge' ) ); - add_action( 'admin_post_ipquery_lookup', array( self::class, 'handle_manual_lookup' ) ); - add_action( 'admin_post_ipquery_export_csv', array( self::class, 'handle_export_csv' ) ); - add_action( 'wp_ajax_ipquery_chart_data', array( self::class, 'ajax_chart_data' ) ); - add_action( 'wp_ajax_ipquery_heatmap_data', array( self::class, 'ajax_heatmap_data' ) ); + add_action( 'admin_post_sva_delete_ip', array( self::class, 'handle_delete_ip' ) ); + add_action( 'admin_post_sva_delete_by_country', array( self::class, 'handle_delete_by_country' ) ); + add_action( 'admin_post_sva_purge', array( self::class, 'handle_purge' ) ); + add_action( 'admin_post_sva_lookup', array( self::class, 'handle_manual_lookup' ) ); + add_action( 'admin_post_sva_export_csv', array( self::class, 'handle_export_csv' ) ); + add_action( 'wp_ajax_sva_chart_data', array( self::class, 'ajax_chart_data' ) ); + add_action( 'wp_ajax_sva_heatmap_data', array( self::class, 'ajax_heatmap_data' ) ); // Schedule daily cleanup cron if not already queued. - if ( ! wp_next_scheduled( 'ipquery_daily_cleanup' ) ) { - wp_schedule_event( time(), 'daily', 'ipquery_daily_cleanup' ); + if ( ! wp_next_scheduled( 'sva_daily_cleanup' ) ) { + wp_schedule_event( time(), 'daily', 'sva_daily_cleanup' ); } - add_action( 'ipquery_daily_cleanup', array( self::class, 'run_cleanup' ) ); + add_action( 'sva_daily_cleanup', array( self::class, 'run_cleanup' ) ); } /** @@ -49,33 +49,33 @@ public static function register_menu(): void { __( 'Visitor Analytics', 'stracini-visitor-analytics' ), __( 'Visitor Analytics', 'stracini-visitor-analytics' ), 'manage_options', - 'ipquery-dashboard', + 'sva-dashboard', array( self::class, 'page_dashboard' ), 'dashicons-location-alt', 81 ); add_submenu_page( - 'ipquery-dashboard', + 'sva-dashboard', __( 'Dashboard', 'stracini-visitor-analytics' ), __( 'Dashboard', 'stracini-visitor-analytics' ), 'manage_options', - 'ipquery-dashboard', + 'sva-dashboard', array( self::class, 'page_dashboard' ) ); add_submenu_page( - 'ipquery-dashboard', + 'sva-dashboard', __( 'Visitors', 'stracini-visitor-analytics' ), __( 'Visitors', 'stracini-visitor-analytics' ), 'manage_options', - 'ipquery-visitors', + 'sva-visitors', array( self::class, 'page_visitors' ) ); add_submenu_page( - 'ipquery-dashboard', + 'sva-dashboard', __( 'Settings', 'stracini-visitor-analytics' ), __( 'Settings', 'stracini-visitor-analytics' ), 'manage_options', - 'ipquery-settings', + 'sva-settings', array( self::class, 'page_settings' ) ); } @@ -92,26 +92,26 @@ public static function enqueue_assets( string $hook ): void { } // Leaflet map library (bundled). - wp_enqueue_style( 'leaflet', IPQUERY_URL . 'assets/css/leaflet.min.css', array(), '1.9.4' ); - wp_enqueue_script( 'leaflet', IPQUERY_URL . 'assets/js/leaflet.min.js', array(), '1.9.4', true ); - wp_enqueue_script( 'leaflet-heat', IPQUERY_URL . 'assets/js/leaflet-heat.js', array( 'leaflet' ), '0.2.0', true ); + wp_enqueue_style( 'leaflet', SVA_URL . 'assets/css/leaflet.min.css', array(), '1.9.4' ); + wp_enqueue_script( 'leaflet', SVA_URL . 'assets/js/leaflet.min.js', array(), '1.9.4', true ); + wp_enqueue_script( 'leaflet-heat', SVA_URL . 'assets/js/leaflet-heat.js', array( 'leaflet' ), '0.2.0', true ); // Chart.js for bar and doughnut charts (bundled). - wp_enqueue_script( 'chartjs', IPQUERY_URL . 'assets/js/chart.umd.min.js', array(), '4.5.1', true ); + wp_enqueue_script( 'chartjs', SVA_URL . 'assets/js/chart.umd.min.js', array(), '4.5.1', true ); // Plugin assets. - wp_enqueue_style( 'ipquery-admin', IPQUERY_URL . 'assets/css/admin.css', array(), IPQUERY_VERSION ); - wp_enqueue_script( 'ipquery-maps', IPQUERY_URL . 'assets/js/ipquery-maps.js', array( 'leaflet', 'leaflet-heat', 'jquery' ), IPQUERY_VERSION, true ); - wp_enqueue_script( 'ipquery-charts', IPQUERY_URL . 'assets/js/ipquery-charts.js', array( 'chartjs', 'jquery' ), IPQUERY_VERSION, true ); + wp_enqueue_style( 'sva-admin', SVA_URL . 'assets/css/admin.css', array(), SVA_VERSION ); + wp_enqueue_script( 'sva-maps', SVA_URL . 'assets/js/sva-maps.js', array( 'leaflet', 'leaflet-heat', 'jquery' ), SVA_VERSION, true ); + wp_enqueue_script( 'sva-charts', SVA_URL . 'assets/js/sva-charts.js', array( 'chartjs', 'jquery' ), SVA_VERSION, true ); wp_localize_script( - 'ipquery-maps', - 'IpQueryData', + 'sva-maps', + 'SvaData', array( 'ajaxUrl' => admin_url( 'admin-ajax.php' ), - 'nonce' => wp_create_nonce( 'ipquery_ajax' ), - 'heatmapAction' => 'ipquery_heatmap_data', - 'chartAction' => 'ipquery_chart_data', + 'nonce' => wp_create_nonce( 'sva_ajax' ), + 'heatmapAction' => 'sva_heatmap_data', + 'chartAction' => 'sva_chart_data', ) ); } @@ -129,7 +129,7 @@ public static function page_dashboard(): void { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Not allowed.', 'stracini-visitor-analytics' ) ); } - include IPQUERY_DIR . 'admin/views/dashboard.php'; + include SVA_DIR . 'admin/views/dashboard.php'; } /** @@ -141,7 +141,7 @@ public static function page_visitors(): void { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Not allowed.', 'stracini-visitor-analytics' ) ); } - include IPQUERY_DIR . 'admin/views/visitors.php'; + include SVA_DIR . 'admin/views/visitors.php'; } /** @@ -153,7 +153,7 @@ public static function page_settings(): void { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Not allowed.', 'stracini-visitor-analytics' ) ); } - include IPQUERY_DIR . 'admin/views/settings.php'; + include SVA_DIR . 'admin/views/settings.php'; } // ------------------------------------------------------------------------- @@ -167,8 +167,8 @@ public static function page_settings(): void { */ public static function handle_settings_save(): void { if ( - ! isset( $_POST['ipquery_settings_nonce'] ) || - ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['ipquery_settings_nonce'] ) ), 'ipquery_save_settings' ) + ! isset( $_POST['sva_settings_nonce'] ) || + ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['sva_settings_nonce'] ) ), 'sva_save_settings' ) ) { return; } @@ -206,15 +206,15 @@ static function () { * @return void */ public static function handle_delete_ip(): void { - check_admin_referer( 'ipquery_delete_ip' ); + check_admin_referer( 'sva_delete_ip' ); if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Not allowed.', 'stracini-visitor-analytics' ) ); } $ip = sanitize_text_field( wp_unslash( $_POST['ip'] ?? '' ) ); if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) { - IpQuery_DB::delete_ip( $ip ); + SVA_DB::delete_ip( $ip ); } - wp_safe_redirect( admin_url( 'admin.php?page=ipquery-visitors&deleted=1' ) ); + wp_safe_redirect( admin_url( 'admin.php?page=sva-visitors&deleted=1' ) ); exit; } @@ -224,7 +224,7 @@ public static function handle_delete_ip(): void { * @return void */ public static function handle_delete_by_country(): void { - check_admin_referer( 'ipquery_delete_by_country' ); + check_admin_referer( 'sva_delete_by_country' ); if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Not allowed.', 'stracini-visitor-analytics' ) ); } @@ -234,20 +234,20 @@ public static function handle_delete_by_country(): void { ); if ( empty( $country_code ) ) { - wp_safe_redirect( admin_url( 'admin.php?page=ipquery-visitors' ) ); + wp_safe_redirect( admin_url( 'admin.php?page=sva-visitors' ) ); exit; } - $deleted = IpQuery_DB::delete_by_country( $country_code ); + $deleted = SVA_DB::delete_by_country( $country_code ); if ( false === $deleted ) { wp_safe_redirect( - admin_url( 'admin.php?page=ipquery-visitors&country_delete_error=1' ) + admin_url( 'admin.php?page=sva-visitors&country_delete_error=1' ) ); exit; } - IpQuery_DB::log_action( + SVA_DB::log_action( sprintf( 'Admin "%s" deleted %d visitor record(s) for country: %s', wp_get_current_user()->user_login, @@ -260,7 +260,7 @@ public static function handle_delete_by_country(): void { wp_safe_redirect( admin_url( - 'admin.php?page=ipquery-visitors' + 'admin.php?page=sva-visitors' . '&country_deleted=' . $deleted_param . '&country_code=' . rawurlencode( $country_code ) ) @@ -274,13 +274,13 @@ public static function handle_delete_by_country(): void { * @return void */ public static function handle_purge(): void { - check_admin_referer( 'ipquery_purge' ); + check_admin_referer( 'sva_purge' ); if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Not allowed.', 'stracini-visitor-analytics' ) ); } $days = max( 1, (int) sanitize_text_field( wp_unslash( $_POST['days'] ?? '90' ) ) ); - $deleted = IpQuery_DB::delete_old_records( $days ); - wp_safe_redirect( admin_url( 'admin.php?page=ipquery-visitors&purged=' . $deleted ) ); + $deleted = SVA_DB::delete_old_records( $days ); + wp_safe_redirect( admin_url( 'admin.php?page=sva-visitors&purged=' . $deleted ) ); exit; } @@ -290,13 +290,13 @@ public static function handle_purge(): void { * @return void */ public static function handle_manual_lookup(): void { - check_admin_referer( 'ipquery_manual_lookup' ); + check_admin_referer( 'sva_manual_lookup' ); if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Not allowed.', 'stracini-visitor-analytics' ) ); } $ip = sanitize_text_field( wp_unslash( $_POST['ip'] ?? '' ) ); if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) { - wp_safe_redirect( admin_url( 'admin.php?page=ipquery-visitors&lookup_error=invalid' ) ); + wp_safe_redirect( admin_url( 'admin.php?page=sva-visitors&lookup_error=invalid' ) ); exit; } @@ -323,10 +323,10 @@ public static function handle_manual_lookup(): void { 'is_datacenter' => (int) ( $response->risk?->isDatacenter ?? 0 ), 'risk_score' => $response->risk?->riskScore ?? 0, ); - IpQuery_DB::upsert( $row ); - wp_safe_redirect( admin_url( 'admin.php?page=ipquery-visitors&lookup_ok=1' ) ); + SVA_DB::upsert( $row ); + wp_safe_redirect( admin_url( 'admin.php?page=sva-visitors&lookup_ok=1' ) ); } catch ( IpQueryException $e ) { - wp_safe_redirect( admin_url( 'admin.php?page=ipquery-visitors&lookup_error=' . rawurlencode( $e->getMessage() ) ) ); + wp_safe_redirect( admin_url( 'admin.php?page=sva-visitors&lookup_error=' . rawurlencode( $e->getMessage() ) ) ); } exit; } @@ -337,7 +337,7 @@ public static function handle_manual_lookup(): void { * @return void */ public static function handle_export_csv(): void { - check_admin_referer( 'ipquery_export_csv' ); + check_admin_referer( 'sva_export_csv' ); if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Not allowed.', 'stracini-visitor-analytics' ) ); } @@ -345,13 +345,13 @@ public static function handle_export_csv(): void { $search = sanitize_text_field( wp_unslash( $_POST['s'] ?? '' ) ); $risk_filter = sanitize_text_field( wp_unslash( $_POST['risk_filter'] ?? '' ) ); - $rows = IpQuery_DB::get_all_for_export( + $rows = SVA_DB::get_all_for_export( array( 'search' => $search, 'risk_filter' => $risk_filter, ) ); - $filename = 'ipquery-visitors-' . gmdate( 'Y-m-d' ) . '.csv'; + $filename = 'sva-visitors-' . gmdate( 'Y-m-d' ) . '.csv'; header( 'Content-Type: text/csv; charset=utf-8' ); header( 'Content-Disposition: attachment; filename="' . $filename . '"' ); @@ -433,13 +433,13 @@ public static function handle_export_csv(): void { * @return void */ public static function ajax_chart_data(): void { - check_ajax_referer( 'ipquery_ajax', 'nonce' ); + check_ajax_referer( 'sva_ajax', 'nonce' ); $data = array( - 'countries' => IpQuery_DB::get_top_countries( 15 ), - 'risk' => IpQuery_DB::get_risk_counts(), + 'countries' => SVA_DB::get_top_countries( 15 ), + 'risk' => SVA_DB::get_risk_counts(), 'totals' => array( - 'visits' => IpQuery_DB::get_total_visits(), - 'unique_ips' => IpQuery_DB::get_unique_ips(), + 'visits' => SVA_DB::get_total_visits(), + 'unique_ips' => SVA_DB::get_unique_ips(), ), ); wp_send_json_success( $data ); @@ -451,8 +451,8 @@ public static function ajax_chart_data(): void { * @return void */ public static function ajax_heatmap_data(): void { - check_ajax_referer( 'ipquery_ajax', 'nonce' ); - $points = IpQuery_DB::get_coordinates_for_heatmap( 500 ); + check_ajax_referer( 'sva_ajax', 'nonce' ); + $points = SVA_DB::get_coordinates_for_heatmap( 500 ); wp_send_json_success( $points ); } @@ -462,8 +462,8 @@ public static function ajax_heatmap_data(): void { * @return void */ public static function run_cleanup(): void { - $settings = get_option( 'ipquery_settings', array() ); + $settings = get_option( 'sva_settings', array() ); $days = (int) ( $settings['retention_days'] ?? 90 ); - IpQuery_DB::delete_old_records( $days ); + SVA_DB::delete_old_records( $days ); } } diff --git a/includes/class-ipquery-db.php b/includes/class-sva-db.php similarity index 94% rename from includes/class-ipquery-db.php rename to includes/class-sva-db.php index 706a35d..b16c4ad 100644 --- a/includes/class-ipquery-db.php +++ b/includes/class-sva-db.php @@ -2,15 +2,15 @@ /** * Database helper — table creation, upsert, and query methods. * - * @package IpQuery + * @package SVA */ defined( 'ABSPATH' ) || exit; /** - * Handles all direct database interactions for the IpQuery plugin. + * Handles all direct database interactions for the SVA plugin. */ -class IpQuery_DB { +class SVA_DB { const DB_VERSION = '1.0.0'; @@ -22,7 +22,7 @@ class IpQuery_DB { public static function install(): void { global $wpdb; - $table = $wpdb->prefix . IPQUERY_TABLE; + $table = $wpdb->prefix . SVA_TABLE; $charset = $wpdb->get_charset_collate(); $sql = "CREATE TABLE {$table} ( @@ -57,11 +57,11 @@ public static function install(): void { require_once ABSPATH . 'wp-admin/includes/upgrade.php'; dbDelta( $sql ); - update_option( 'ipquery_db_version', self::DB_VERSION ); + update_option( 'sva_db_version', self::DB_VERSION ); - if ( false === get_option( 'ipquery_settings' ) ) { + if ( false === get_option( 'sva_settings' ) ) { update_option( - 'ipquery_settings', + 'sva_settings', array( 'tracking_enabled' => true, 'track_logged_in' => false, @@ -88,7 +88,7 @@ public static function deactivate(): void {} */ public static function uninstall(): void { global $wpdb; - $table = $wpdb->prefix . IPQUERY_TABLE; + $table = $wpdb->prefix . SVA_TABLE; $wpdb->query( "DROP TABLE IF EXISTS {$table}" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange } @@ -104,7 +104,7 @@ public static function uninstall(): void { */ public static function upsert( array $data ): void { global $wpdb; - $table = $wpdb->prefix . IPQUERY_TABLE; + $table = $wpdb->prefix . SVA_TABLE; $now = current_time( 'mysql' ); $existing = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching @@ -140,7 +140,7 @@ public static function upsert( array $data ): void { */ public static function get_total_visits(): int { global $wpdb; - $table = $wpdb->prefix . IPQUERY_TABLE; + $table = $wpdb->prefix . SVA_TABLE; return (int) $wpdb->get_var( "SELECT SUM(visit_count) FROM {$table}" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching } @@ -151,7 +151,7 @@ public static function get_total_visits(): int { */ public static function get_unique_ips(): int { global $wpdb; - $table = $wpdb->prefix . IPQUERY_TABLE; + $table = $wpdb->prefix . SVA_TABLE; return (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$table}" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching } @@ -162,7 +162,7 @@ public static function get_unique_ips(): int { */ public static function get_risk_counts(): array { global $wpdb; - $table = $wpdb->prefix . IPQUERY_TABLE; + $table = $wpdb->prefix . SVA_TABLE; return array( 'vpn' => (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$table} WHERE is_vpn = 1" ), // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching 'proxy' => (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$table} WHERE is_proxy = 1" ), // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching @@ -180,7 +180,7 @@ public static function get_risk_counts(): array { */ public static function get_top_countries( int $limit = 10 ): array { global $wpdb; - $table = $wpdb->prefix . IPQUERY_TABLE; + $table = $wpdb->prefix . SVA_TABLE; $sql = $wpdb->prepare( "SELECT country, country_code, SUM(visit_count) AS visits FROM {$table} WHERE country_code IS NOT NULL GROUP BY country_code ORDER BY visits DESC LIMIT %d", $limit ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $result = $wpdb->get_results( $sql, ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared return is_array( $result ) ? $result : array(); @@ -194,7 +194,7 @@ public static function get_top_countries( int $limit = 10 ): array { */ public static function get_top_cities( int $limit = 10 ): array { global $wpdb; - $table = $wpdb->prefix . IPQUERY_TABLE; + $table = $wpdb->prefix . SVA_TABLE; $sql = $wpdb->prepare( "SELECT city, country, country_code, SUM(visit_count) AS visits FROM {$table} WHERE city IS NOT NULL AND city != '' GROUP BY city, country_code ORDER BY visits DESC LIMIT %d", $limit ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $result = $wpdb->get_results( $sql, ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared return is_array( $result ) ? $result : array(); @@ -208,7 +208,7 @@ public static function get_top_cities( int $limit = 10 ): array { */ public static function get_coordinates_for_heatmap( int $limit = 500 ): array { global $wpdb; - $table = $wpdb->prefix . IPQUERY_TABLE; + $table = $wpdb->prefix . SVA_TABLE; $sql = $wpdb->prepare( "SELECT latitude, longitude, visit_count AS intensity FROM {$table} WHERE latitude IS NOT NULL AND longitude IS NOT NULL ORDER BY visit_count DESC LIMIT %d", $limit ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $result = $wpdb->get_results( $sql, ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared return is_array( $result ) ? $result : array(); @@ -222,7 +222,7 @@ public static function get_coordinates_for_heatmap( int $limit = 500 ): array { */ public static function get_visitors( array $args = array() ): array { global $wpdb; - $table = $wpdb->prefix . IPQUERY_TABLE; + $table = $wpdb->prefix . SVA_TABLE; $defaults = array( 'per_page' => 25, @@ -288,7 +288,7 @@ public static function get_visitors( array $args = array() ): array { */ public static function delete_old_records( int $days ): int { global $wpdb; - $table = $wpdb->prefix . IPQUERY_TABLE; + $table = $wpdb->prefix . SVA_TABLE; $sql = $wpdb->prepare( "DELETE FROM {$table} WHERE last_seen < DATE_SUB(NOW(), INTERVAL %d DAY)", $days ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared return (int) $wpdb->rows_affected; @@ -302,7 +302,7 @@ public static function delete_old_records( int $days ): int { */ public static function delete_ip( string $ip ): void { global $wpdb; - $table = $wpdb->prefix . IPQUERY_TABLE; + $table = $wpdb->prefix . SVA_TABLE; $wpdb->delete( $table, array( 'ip' => $ip ), array( '%s' ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching } @@ -315,7 +315,7 @@ public static function delete_ip( string $ip ): void { public static function log_action( string $message ): void { if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log - error_log( '[IpQuery] ' . $message ); + error_log( '[SVA] ' . $message ); } } @@ -327,7 +327,7 @@ public static function log_action( string $message ): void { */ public static function delete_by_country( string $country_code ): int|false { global $wpdb; - $table = $wpdb->prefix . IPQUERY_TABLE; + $table = $wpdb->prefix . SVA_TABLE; return $wpdb->delete( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $table, array( 'country_code' => sanitize_text_field( $country_code ) ), @@ -342,7 +342,7 @@ public static function delete_by_country( string $country_code ): int|false { */ public static function get_distinct_countries(): array { global $wpdb; - $table = $wpdb->prefix . IPQUERY_TABLE; + $table = $wpdb->prefix . SVA_TABLE; $result = $wpdb->get_results( "SELECT DISTINCT country, country_code FROM {$table} WHERE country_code IS NOT NULL AND country_code != '' ORDER BY country ASC", ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared return is_array( $result ) ? $result : array(); } @@ -355,7 +355,7 @@ public static function get_distinct_countries(): array { */ public static function get_all_for_export( array $args = array() ): array { global $wpdb; - $table = $wpdb->prefix . IPQUERY_TABLE; + $table = $wpdb->prefix . SVA_TABLE; $defaults = array( 'orderby' => 'last_seen', diff --git a/includes/class-ipquery-tracker.php b/includes/class-sva-tracker.php similarity index 94% rename from includes/class-ipquery-tracker.php rename to includes/class-sva-tracker.php index 6d0613b..b1588d2 100644 --- a/includes/class-ipquery-tracker.php +++ b/includes/class-sva-tracker.php @@ -2,7 +2,7 @@ /** * Visitor tracker — captures IP addresses and defers API enrichment to shutdown. * - * @package IpQuery + * @package SVA */ defined( 'ABSPATH' ) || exit; @@ -13,7 +13,7 @@ /** * Hooks into WordPress request handling to capture and enrich visitor IPs. */ -class IpQuery_Tracker { +class SVA_Tracker { /** * Plugin settings loaded from the database. @@ -70,7 +70,7 @@ public static function maybe_track(): void { } } - $transient_key = 'ipq_' . md5( $ip ); + $transient_key = 'sva_' . md5( $ip ); if ( get_transient( $transient_key ) ) { self::bump_visit( $ip ); return; @@ -118,12 +118,12 @@ private static function lookup_and_store( string $ip, string $transient_key ): v 'risk_score' => $response->risk?->riskScore ?? 0, ); - IpQuery_DB::upsert( $row ); + SVA_DB::upsert( $row ); set_transient( $transient_key, 1, HOUR_IN_SECONDS ); } catch ( IpQueryException $e ) { - error_log( '[IpQuery WP] ' . $e->getMessage() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log + error_log( '[SVA] ' . $e->getMessage() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log } } @@ -135,7 +135,7 @@ private static function lookup_and_store( string $ip, string $transient_key ): v */ private static function bump_visit( string $ip ): void { global $wpdb; - $table = $wpdb->prefix . IPQUERY_TABLE; + $table = $wpdb->prefix . SVA_TABLE; $sql = $wpdb->prepare( "UPDATE {$table} SET visit_count = visit_count + 1, last_seen = %s WHERE ip = %s", current_time( 'mysql' ), $ip ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared } diff --git a/ipquery.php b/ipquery.php deleted file mode 100644 index a722e35..0000000 --- a/ipquery.php +++ /dev/null @@ -1,71 +0,0 @@ -assertSame( '1.0.0', IpQuery_DB::DB_VERSION ); + $this->assertSame( '1.0.0', SVA_DB::DB_VERSION ); } // ------------------------------------------------------------------------- @@ -63,7 +63,7 @@ static function ( array $args, array $defaults ): array { } ); - $result = IpQuery_DB::get_visitors( [] ); + $result = SVA_DB::get_visitors( [] ); $this->assertArrayHasKey( 'rows', $result ); $this->assertArrayHasKey( 'total', $result ); @@ -83,7 +83,7 @@ static function ( array $args, array $defaults ): array { $validColumns = ['last_seen', 'first_seen', 'visit_count', 'country', 'risk_score', 'ip']; foreach ( $validColumns as $column ) { - $result = IpQuery_DB::get_visitors( ['orderby' => $column] ); + $result = SVA_DB::get_visitors( ['orderby' => $column] ); $this->assertArrayHasKey( 'rows', $result, "Expected 'rows' key for orderby=$column" ); } } @@ -118,7 +118,7 @@ static function ( array $args, array $defaults ): array { } ); - IpQuery_DB::get_visitors( ['orderby' => 'malicious_column; DROP TABLE--'] ); + SVA_DB::get_visitors( ['orderby' => 'malicious_column; DROP TABLE--'] ); $this->assertStringContainsString( 'last_seen', $wpdb->lastQuery ); $this->assertStringNotContainsString( 'malicious_column', $wpdb->lastQuery ); @@ -154,7 +154,7 @@ static function ( array $args, array $defaults ): array { } ); - IpQuery_DB::get_visitors( ['order' => 'INVALID; DROP TABLE--'] ); + SVA_DB::get_visitors( ['order' => 'INVALID; DROP TABLE--'] ); $this->assertStringContainsString( ' DESC', $wpdb->lastQuery ); $this->assertStringNotContainsString( 'INVALID', $wpdb->lastQuery ); diff --git a/tests/unit/TrackerTest.php b/tests/unit/TrackerTest.php index 5da601e..3c92099 100644 --- a/tests/unit/TrackerTest.php +++ b/tests/unit/TrackerTest.php @@ -7,7 +7,7 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -#[CoversClass(IpQuery_Tracker::class)] +#[CoversClass(SVA_Tracker::class)] class TrackerTest extends TestCase { private array $serverBackup = []; @@ -40,51 +40,51 @@ public function test_cloudflare_header_takes_priority(): void { $_SERVER['HTTP_X_REAL_IP'] = '5.6.7.8'; $_SERVER['REMOTE_ADDR'] = '9.10.11.12'; - $this->assertSame( '1.2.3.4', IpQuery_Tracker::get_client_ip() ); + $this->assertSame( '1.2.3.4', SVA_Tracker::get_client_ip() ); } public function test_x_real_ip_used_when_no_cloudflare(): void { $_SERVER['HTTP_X_REAL_IP'] = '5.6.7.8'; $_SERVER['REMOTE_ADDR'] = '9.10.11.12'; - $this->assertSame( '5.6.7.8', IpQuery_Tracker::get_client_ip() ); + $this->assertSame( '5.6.7.8', SVA_Tracker::get_client_ip() ); } public function test_x_forwarded_for_returns_first_ip_in_list(): void { $_SERVER['HTTP_X_FORWARDED_FOR'] = '1.2.3.4, 5.6.7.8, 9.10.11.12'; $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; - $this->assertSame( '1.2.3.4', IpQuery_Tracker::get_client_ip() ); + $this->assertSame( '1.2.3.4', SVA_Tracker::get_client_ip() ); } public function test_x_forwarded_for_strips_whitespace(): void { $_SERVER['HTTP_X_FORWARDED_FOR'] = ' 1.2.3.4 , 5.6.7.8'; - $this->assertSame( '1.2.3.4', IpQuery_Tracker::get_client_ip() ); + $this->assertSame( '1.2.3.4', SVA_Tracker::get_client_ip() ); } public function test_remote_addr_is_final_fallback(): void { $_SERVER['REMOTE_ADDR'] = '203.0.113.42'; - $this->assertSame( '203.0.113.42', IpQuery_Tracker::get_client_ip() ); + $this->assertSame( '203.0.113.42', SVA_Tracker::get_client_ip() ); } public function test_invalid_ip_in_cf_header_falls_through_to_next_candidate(): void { $_SERVER['HTTP_CF_CONNECTING_IP'] = 'not-an-ip'; $_SERVER['REMOTE_ADDR'] = '1.2.3.4'; - $this->assertSame( '1.2.3.4', IpQuery_Tracker::get_client_ip() ); + $this->assertSame( '1.2.3.4', SVA_Tracker::get_client_ip() ); } public function test_ipv6_address_is_accepted(): void { $_SERVER['REMOTE_ADDR'] = '2001:db8::1'; - $this->assertSame( '2001:db8::1', IpQuery_Tracker::get_client_ip() ); + $this->assertSame( '2001:db8::1', SVA_Tracker::get_client_ip() ); } public function test_returns_empty_string_when_no_valid_ip_present(): void { // All candidates absent. - $this->assertSame( '', IpQuery_Tracker::get_client_ip() ); + $this->assertSame( '', SVA_Tracker::get_client_ip() ); } // ------------------------------------------------------------------------- @@ -98,8 +98,8 @@ public function test_maybe_track_skips_ajax_requests(): void { Functions\when( 'wp_doing_cron' )->justReturn( false ); Functions\expect( 'is_user_logged_in' )->never(); - IpQuery_Tracker::init( ['tracking_enabled' => true] ); - IpQuery_Tracker::maybe_track(); + SVA_Tracker::init( ['tracking_enabled' => true] ); + SVA_Tracker::maybe_track(); } public function test_maybe_track_skips_cron_requests(): void { @@ -109,8 +109,8 @@ public function test_maybe_track_skips_cron_requests(): void { Functions\when( 'wp_doing_cron' )->justReturn( true ); Functions\expect( 'is_user_logged_in' )->never(); - IpQuery_Tracker::init( ['tracking_enabled' => true] ); - IpQuery_Tracker::maybe_track(); + SVA_Tracker::init( ['tracking_enabled' => true] ); + SVA_Tracker::maybe_track(); } public function test_maybe_track_skips_ip_on_exclusion_list(): void { @@ -123,12 +123,12 @@ public function test_maybe_track_skips_ip_on_exclusion_list(): void { Functions\when( 'is_user_logged_in' )->justReturn( false ); Functions\expect( 'get_transient' )->never(); - IpQuery_Tracker::init( [ + SVA_Tracker::init( [ 'tracking_enabled' => true, 'excluded_ips' => "1.2.3.4\n5.6.7.8", 'lookup_private_ips' => true, ] ); - IpQuery_Tracker::maybe_track(); + SVA_Tracker::maybe_track(); } public function test_maybe_track_skips_private_ip_when_setting_off(): void { @@ -141,12 +141,12 @@ public function test_maybe_track_skips_private_ip_when_setting_off(): void { Functions\when( 'is_user_logged_in' )->justReturn( false ); Functions\expect( 'get_transient' )->never(); - IpQuery_Tracker::init( [ + SVA_Tracker::init( [ 'tracking_enabled' => true, 'excluded_ips' => '', 'lookup_private_ips' => false, ] ); - IpQuery_Tracker::maybe_track(); + SVA_Tracker::maybe_track(); } public function test_maybe_track_registers_shutdown_on_transient_miss(): void { @@ -166,12 +166,12 @@ static function ( string $hook, $callback ) use ( &$shutdownRegistered ): void { } ); - IpQuery_Tracker::init( [ + SVA_Tracker::init( [ 'tracking_enabled' => true, 'excluded_ips' => '', 'lookup_private_ips' => false, ] ); - IpQuery_Tracker::maybe_track(); + SVA_Tracker::maybe_track(); $this->assertTrue( $shutdownRegistered, 'Expected a shutdown action to be registered for API lookup.' ); } From 0d853b02f420d5a9d31c4a52a537f2060e7dccd9 Mon Sep 17 00:00:00 2001 From: Guilherme Branco Stracini Date: Sat, 23 May 2026 12:58:43 +0100 Subject: [PATCH 5/7] chore: rename plugin from IpQuery to SVA Refactor code to transition from 'IpQuery' branding to 'SVA' (Stracini Visitor Analytics). Update file names, variables, CSS selectors, HTML classes, and function names throughout the codebase. This change aligns the code with the plugin's new name and branding, providing a consistent experience for users and improving maintainability. --- .github/workflows/release.yml | 6 +- .github/workflows/test.yml | 6 +- admin/views/dashboard.php | 156 +++++++------- admin/views/settings.php | 44 ++-- admin/views/visitors.php | 190 +++++++++--------- assets/css/admin.css | 116 +++++------ .../js/{ipquery-charts.js => sva-charts.js} | 12 +- assets/js/{ipquery-maps.js => sva-maps.js} | 12 +- 8 files changed, 271 insertions(+), 271 deletions(-) rename assets/js/{ipquery-charts.js => sva-charts.js} (92%) rename assets/js/{ipquery-maps.js => sva-maps.js} (86%) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 28b5d01..916216a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -117,15 +117,15 @@ jobs: env: VERSION: ${{ needs.version.outputs.fullSemVer }} run: | - sed -i "s/^ \* Version:.*/ * Version: ${VERSION}/" ipquery.php - sed -i "s/define( 'IPQUERY_VERSION',[^)]*)/define( 'IPQUERY_VERSION', '${VERSION}' )/" ipquery.php + sed -i "s/^ \* Version:.*/ * Version: ${VERSION}/" stracini-visitor-analytics.php + sed -i "s/define( 'SVA_VERSION',[^)]*)/define( 'SVA_VERSION', '${VERSION}' )/" stracini-visitor-analytics.php sed -i "s/^Stable tag:.*/Stable tag: ${VERSION}/" readme.txt - name: Commit version bump, tag, and push env: VERSION: ${{ needs.version.outputs.fullSemVer }} run: | - git add ipquery.php readme.txt + git add stracini-visitor-analytics.php readme.txt # Commit only when the version files actually changed. git diff --cached --quiet \ || git commit -m "chore: bump version to ${VERSION} [skip ci]" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a9b590d..e9f182c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -71,12 +71,12 @@ jobs: - name: Stage plugin under its slug directory run: | - mkdir -p /tmp/ipquery - git archive HEAD | tar -x -C /tmp/ipquery + mkdir -p /tmp/stracini-visitor-analytics + git archive HEAD | tar -x -C /tmp/stracini-visitor-analytics - name: Run WordPress Plugin Check uses: wordpress/plugin-check-action@v1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} wp-version: 'latest' - build-dir: /tmp/ipquery + build-dir: /tmp/stracini-visitor-analytics diff --git a/admin/views/dashboard.php b/admin/views/dashboard.php index 6a17c01..24b72b0 100644 --- a/admin/views/dashboard.php +++ b/admin/views/dashboard.php @@ -2,12 +2,12 @@ /** * Dashboard admin view — stat cards, heatmap, and charts. * - * @package IpQuery + * @package SVA */ defined( 'ABSPATH' ) || exit; ?> -
+

@@ -15,83 +15,83 @@
-
-
-
-
- - +
+
+
+
+ +
-
-
-
- - +
+
+
+ +
-
-
-
- - +
+
+
+ +
-
-
-
+
+
+
0 - ? round( ( ( $ipquery_risk_counts['vpn'] + $ipquery_risk_counts['proxy'] + $ipquery_risk_counts['tor'] ) / $ipquery_unique_ips ) * 100, 1 ) + $sva_risky_pct = $sva_unique_ips > 0 + ? round( ( ( $sva_risk_counts['vpn'] + $sva_risk_counts['proxy'] + $sva_risk_counts['tor'] ) / $sva_unique_ips ) * 100, 1 ) : 0; ?> - % - + % +
-
+
-
+

-
+
-
+

-
- +
+
-
+
-
+

-
- +
+
-
+

- +
@@ -100,22 +100,22 @@ - + - + - - + + @@ -126,10 +126,10 @@ -
-
+
+

-
- - + <?php echo esc_attr( $ipquery_row['country_code'] ); ?> - + 0 ? esc_html( round( ( $ipquery_row['visits'] / $ipquery_total_visits ) * 100, 1 ) ) . '%' : '—'; ?> 0 ? esc_html( round( ( $sva_row['visits'] / $sva_total_visits ) * 100, 1 ) ) . '%' : '—'; ?>
+
@@ -139,23 +139,23 @@ - + - + - + - - + + @@ -165,51 +165,51 @@ -
-
+
+

-
+
__( 'VPN', 'stracini-visitor-analytics' ), - 'count' => $ipquery_risk_counts['vpn'], + 'count' => $sva_risk_counts['vpn'], 'icon' => 'lock', 'class' => 'orange', ), array( 'label' => __( 'Proxy', 'stracini-visitor-analytics' ), - 'count' => $ipquery_risk_counts['proxy'], + 'count' => $sva_risk_counts['proxy'], 'icon' => 'update', 'class' => 'red', ), array( 'label' => __( 'Tor', 'stracini-visitor-analytics' ), - 'count' => $ipquery_risk_counts['tor'], + 'count' => $sva_risk_counts['tor'], 'icon' => 'hidden', 'class' => 'red', ), array( 'label' => __( 'Datacenter', 'stracini-visitor-analytics' ), - 'count' => $ipquery_risk_counts['datacenter'], + 'count' => $sva_risk_counts['datacenter'], 'icon' => 'cloud', 'class' => 'blue', ), array( 'label' => __( 'Mobile', 'stracini-visitor-analytics' ), - 'count' => $ipquery_risk_counts['mobile'], + 'count' => $sva_risk_counts['mobile'], 'icon' => 'smartphone', 'class' => 'green', ), ); - foreach ( $ipquery_risk_items as $ipquery_item ) : + foreach ( $sva_risk_items as $sva_item ) : ?> -
- - - - 0 ) : ?> - % +
+ + + + 0 ) : ?> + %
diff --git a/admin/views/settings.php b/admin/views/settings.php index b1a6b8c..fcf49dd 100644 --- a/admin/views/settings.php +++ b/admin/views/settings.php @@ -2,12 +2,12 @@ /** * Settings admin view. * - * @package IpQuery + * @package SVA */ defined( 'ABSPATH' ) || exit; ?> -
+

@@ -15,8 +15,8 @@
true, 'track_logged_in' => false, 'track_admins' => false, @@ -24,11 +24,11 @@ 'retention_days' => 90, 'lookup_private_ips' => false, ); - $ipquery_settings = wp_parse_args( $ipquery_raw, $ipquery_defaults ); + $sva_settings = wp_parse_args( $sva_raw, $sva_defaults ); ?>
- +

- - + <?php echo esc_attr( $ipquery_row['country_code'] ); ?> - + 0 ? esc_html( round( ( $ipquery_row['visits'] / $ipquery_total_visits ) * 100, 1 ) ) . '%' : '—'; ?> 0 ? esc_html( round( ( $sva_row['visits'] / $sva_total_visits ) * 100, 1 ) ) . '%' : '—'; ?>
@@ -36,7 +36,7 @@ @@ -57,7 +57,7 @@ @@ -67,7 +67,7 @@ @@ -78,7 +78,7 @@ @@ -89,7 +89,7 @@ @@ -146,26 +146,26 @@ - + diff --git a/admin/views/visitors.php b/admin/views/visitors.php index df2fb10..2ad9c2f 100644 --- a/admin/views/visitors.php +++ b/admin/views/visitors.php @@ -2,12 +2,12 @@ /** * Visitors admin view — searchable, sortable IP log with lookup and purge tools. * - * @package IpQuery + * @package SVA */ defined( 'ABSPATH' ) || exit; ?> -
+

@@ -27,8 +27,8 @@ // translators: %s is the error message returned by the lookup. echo '

' . esc_html( sprintf( __( 'Lookup error: %s', 'stracini-visitor-analytics' ), urldecode( sanitize_text_field( wp_unslash( $_GET['lookup_error'] ) ) ) ) ) . '

'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended elseif ( isset( $_GET['country_deleted'] ) && 'false' !== $_GET['country_deleted'] ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended - $ipquery_deleted_count = (int) $_GET['country_deleted']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended - $ipquery_deleted_country = esc_html( strtoupper( sanitize_text_field( wp_unslash( $_GET['country_code'] ?? '' ) ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $sva_deleted_count = (int) $_GET['country_deleted']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $sva_deleted_country = esc_html( strtoupper( sanitize_text_field( wp_unslash( $_GET['country_code'] ?? '' ) ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended printf( '

' . esc_html( sprintf( @@ -36,11 +36,11 @@ _n( '%1$d record deleted for country: %2$s.', '%1$d records deleted for country: %2$s.', - $ipquery_deleted_count, + $sva_deleted_count, 'stracini-visitor-analytics' ), - $ipquery_deleted_count, - $ipquery_deleted_country + $sva_deleted_count, + $sva_deleted_country ) ) . '

' ); @@ -50,9 +50,9 @@ ?> -
- - +
+ + @@ -80,50 +80,50 @@ class="regular-text"> if ( ! empty( $_GET['s'] ) || ! empty( $_GET['risk_filter'] ) ) : // phpcs:enable WordPress.Security.NonceVerification.Recommended ?> - + -
- - + + +
-
- - + + + - +
$ipquery_per_page, - 'page' => $ipquery_current_page, - 'orderby' => $ipquery_orderby, - 'order' => $ipquery_order, + 'per_page' => $sva_per_page, + 'page' => $sva_current_page, + 'orderby' => $sva_orderby, + 'order' => $sva_order, 'search' => sanitize_text_field( wp_unslash( $_GET['s'] ?? '' ) ), // phpcs:ignore WordPress.Security.NonceVerification.Recommended - 'risk_filter' => $ipquery_risk_filter, + 'risk_filter' => $sva_risk_filter, ) ); - $ipquery_rows = $ipquery_result['rows']; - $ipquery_total = $ipquery_result['total']; - $ipquery_total_pages = ceil( $ipquery_total / $ipquery_per_page ); + $sva_rows = $sva_result['rows']; + $sva_total = $sva_result['total']; + $sva_total_pages = ceil( $sva_total / $sva_per_page ); /** * Returns a sortable column header link. @@ -134,7 +134,7 @@ class="regular-text"> * @param string $current_order Currently active sort direction. * @return string Safe HTML anchor. */ - function ipquery_sortable_col( string $col, string $label, string $current_orderby, string $current_order ): string { + function sva_sortable_col( string $col, string $label, string $current_orderby, string $current_order ): string { $is_sorted = $col === $current_orderby; $next_order = ( $is_sorted && 'ASC' === $current_order ) ? 'DESC' : 'ASC'; $url = add_query_arg( @@ -148,90 +148,90 @@ function ipquery_sortable_col( string $col, string $label, string $current_order } ?> -

+

' . esc_html( number_format_i18n( $ipquery_total ) ) . '' + esc_html( _n( '%s record found.', '%s records found.', $sva_total, 'stracini-visitor-analytics' ) ), + '' . esc_html( number_format_i18n( $sva_total ) ) . '' ); ?>

- +
- - + + - - - - + + + + - + array( 'class' => true ), ); - foreach ( $ipquery_rows as $ipquery_row ) : - $ipquery_flags = array(); - if ( $ipquery_row['is_vpn'] ) { - $ipquery_flags[] = 'VPN'; + foreach ( $sva_rows as $sva_row ) : + $sva_flags = array(); + if ( $sva_row['is_vpn'] ) { + $sva_flags[] = 'VPN'; } - if ( $ipquery_row['is_proxy'] ) { - $ipquery_flags[] = 'Proxy'; + if ( $sva_row['is_proxy'] ) { + $sva_flags[] = 'Proxy'; } - if ( $ipquery_row['is_tor'] ) { - $ipquery_flags[] = 'Tor'; + if ( $sva_row['is_tor'] ) { + $sva_flags[] = 'Tor'; } - if ( $ipquery_row['is_datacenter'] ) { - $ipquery_flags[] = 'DC'; + if ( $sva_row['is_datacenter'] ) { + $sva_flags[] = 'DC'; } - if ( $ipquery_row['is_mobile'] ) { - $ipquery_flags[] = 'Mobile'; + if ( $sva_row['is_mobile'] ) { + $sva_flags[] = 'Mobile'; } - $ipquery_score = (int) $ipquery_row['risk_score']; - $ipquery_score_cls = $ipquery_score >= 80 ? 'red' : ( $ipquery_score >= 40 ? 'orange' : 'green' ); - $ipquery_location = array_filter( array( $ipquery_row['city'], $ipquery_row['state'], $ipquery_row['country'] ) ); + $sva_score = (int) $sva_row['risk_score']; + $sva_score_cls = $sva_score >= 80 ? 'red' : ( $sva_score >= 40 ? 'orange' : 'green' ); + $sva_location = array_filter( array( $sva_row['city'], $sva_row['state'], $sva_row['country'] ) ); ?> - + - + - - - - + + + +
- - + <?php echo esc_attr( $ipquery_row['country_code'] ); ?> - + Clean'; + echo 'Clean'; } ?>
- - - + + +
- 1 ) : ?> + 1 ) : ?>
add_query_arg( 'paged', '%#%' ), 'format' => '', - 'current' => $ipquery_current_page, - 'total' => $ipquery_total_pages, + 'current' => $sva_current_page, + 'total' => $sva_total_pages, 'prev_text' => '«', 'next_text' => '»', ) @@ -266,11 +266,11 @@ function ipquery_sortable_col( string $col, string $label, string $current_order -
+

- - + +
-
+

- - + +