Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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]"
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<div align="center">

# 🌍 IpQuery
# 🌍 Stracini Visitor Analytics with IpQuery

**Track and analyse every visitor. Visualise traffic. Detect threats.**

Expand All @@ -16,6 +16,11 @@ A WordPress plugin that enriches visitor IP addresses with real-time geolocation

</div>

> **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
Expand All @@ -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:

Expand Down Expand Up @@ -136,7 +141,7 @@ The plugin automatically:

## ⚙️ Configuration

Navigate to **IpQuery → Settings** to configure:
Navigate to **Visitor Analytics → Settings** to configure:

| Setting | Default | Description |
|---|---|---|
Expand Down
156 changes: 78 additions & 78 deletions admin/views/dashboard.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,96 +2,96 @@
/**
* Dashboard admin view — stat cards, heatmap, and charts.
*
* @package IpQuery
* @package SVA
*/

defined( 'ABSPATH' ) || exit; ?>

<div class="wrap ipquery-wrap">
<div class="wrap sva-wrap">
<h1 class="wp-heading-inline">
<span class="dashicons dashicons-location-alt"></span>
<?php esc_html_e( 'Visitor Analytics — Dashboard', 'stracini-visitor-analytics' ); ?>
</h1>
<hr class="wp-header-end">

<?php
$ipquery_total_visits = IpQuery_DB::get_total_visits();
$ipquery_unique_ips = IpQuery_DB::get_unique_ips();
$ipquery_risk_counts = IpQuery_DB::get_risk_counts();
$ipquery_top_countries = IpQuery_DB::get_top_countries( 10 );
$ipquery_top_cities = IpQuery_DB::get_top_cities( 10 );
$sva_total_visits = SVA_DB::get_total_visits();
$sva_unique_ips = SVA_DB::get_unique_ips();
$sva_risk_counts = SVA_DB::get_risk_counts();
$sva_top_countries = SVA_DB::get_top_countries( 10 );
$sva_top_cities = SVA_DB::get_top_cities( 10 );
?>

<!-- Stat cards -->
<div class="ipquery-cards">
<div class="ipquery-card ipquery-card--blue">
<div class="ipquery-card__icon dashicons dashicons-admin-users"></div>
<div class="ipquery-card__body">
<span class="ipquery-card__value"><?php echo esc_html( number_format_i18n( $ipquery_total_visits ) ); ?></span>
<span class="ipquery-card__label"><?php esc_html_e( 'Total Visits', 'stracini-visitor-analytics' ); ?></span>
<div class="sva-cards">
<div class="sva-card sva-card--blue">
<div class="sva-card__icon dashicons dashicons-admin-users"></div>
<div class="sva-card__body">
<span class="sva-card__value"><?php echo esc_html( number_format_i18n( $sva_total_visits ) ); ?></span>
<span class="sva-card__label"><?php esc_html_e( 'Total Visits', 'stracini-visitor-analytics' ); ?></span>
</div>
</div>
<div class="ipquery-card ipquery-card--green">
<div class="ipquery-card__icon dashicons dashicons-networking"></div>
<div class="ipquery-card__body">
<span class="ipquery-card__value"><?php echo esc_html( number_format_i18n( $ipquery_unique_ips ) ); ?></span>
<span class="ipquery-card__label"><?php esc_html_e( 'Unique IPs', 'stracini-visitor-analytics' ); ?></span>
<div class="sva-card sva-card--green">
<div class="sva-card__icon dashicons dashicons-networking"></div>
<div class="sva-card__body">
<span class="sva-card__value"><?php echo esc_html( number_format_i18n( $sva_unique_ips ) ); ?></span>
<span class="sva-card__label"><?php esc_html_e( 'Unique IPs', 'stracini-visitor-analytics' ); ?></span>
</div>
</div>
<div class="ipquery-card ipquery-card--orange">
<div class="ipquery-card__icon dashicons dashicons-shield-alt"></div>
<div class="ipquery-card__body">
<span class="ipquery-card__value"><?php echo esc_html( number_format_i18n( $ipquery_risk_counts['vpn'] + $ipquery_risk_counts['proxy'] + $ipquery_risk_counts['tor'] ) ); ?></span>
<span class="ipquery-card__label"><?php esc_html_e( 'VPN / Proxy / Tor', 'stracini-visitor-analytics' ); ?></span>
<div class="sva-card sva-card--orange">
<div class="sva-card__icon dashicons dashicons-shield-alt"></div>
<div class="sva-card__body">
<span class="sva-card__value"><?php echo esc_html( number_format_i18n( $sva_risk_counts['vpn'] + $sva_risk_counts['proxy'] + $sva_risk_counts['tor'] ) ); ?></span>
<span class="sva-card__label"><?php esc_html_e( 'VPN / Proxy / Tor', 'stracini-visitor-analytics' ); ?></span>
</div>
</div>
<div class="ipquery-card ipquery-card--red">
<div class="ipquery-card__icon dashicons dashicons-warning"></div>
<div class="ipquery-card__body">
<div class="sva-card sva-card--red">
<div class="sva-card__icon dashicons dashicons-warning"></div>
<div class="sva-card__body">
<?php
$ipquery_risky_pct = $ipquery_unique_ips > 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;
?>
<span class="ipquery-card__value"><?php echo esc_html( $ipquery_risky_pct ); ?>%</span>
<span class="ipquery-card__label"><?php esc_html_e( 'Risk Rate', 'stracini-visitor-analytics' ); ?></span>
<span class="sva-card__value"><?php echo esc_html( $sva_risky_pct ); ?>%</span>
<span class="sva-card__label"><?php esc_html_e( 'Risk Rate', 'stracini-visitor-analytics' ); ?></span>
</div>
</div>
</div>

<!-- Map + charts row -->
<div class="ipquery-row">
<div class="sva-row">

<!-- World heatmap -->
<div class="ipquery-panel ipquery-panel--wide">
<div class="sva-panel sva-panel--wide">
<h2><?php esc_html_e( 'Visitor Heatmap', 'stracini-visitor-analytics' ); ?></h2>
<div id="ipquery-map" style="height:420px;"></div>
<div id="sva-map" style="height:420px;"></div>
</div>

<!-- Country chart -->
<div class="ipquery-panel ipquery-panel--narrow">
<div class="sva-panel sva-panel--narrow">
<h2><?php esc_html_e( 'Top Countries', 'stracini-visitor-analytics' ); ?></h2>
<div class="ipquery-chart-wrap" style="position:relative;height:390px;overflow:hidden;">
<canvas id="ipquery-country-chart"></canvas>
<div class="sva-chart-wrap" style="position:relative;height:390px;overflow:hidden;">
<canvas id="sva-country-chart"></canvas>
</div>
</div>

</div>

<!-- Risk breakdown row -->
<div class="ipquery-row">
<div class="sva-row">

<div class="ipquery-panel ipquery-panel--half">
<div class="sva-panel sva-panel--half">
<h2><?php esc_html_e( 'Risk Breakdown', 'stracini-visitor-analytics' ); ?></h2>
<div class="ipquery-chart-wrap" style="position:relative;height:260px;overflow:hidden;">
<canvas id="ipquery-risk-chart"></canvas>
<div class="sva-chart-wrap" style="position:relative;height:260px;overflow:hidden;">
<canvas id="sva-risk-chart"></canvas>
</div>
</div>

<!-- Country table -->
<div class="ipquery-panel ipquery-panel--half">
<div class="sva-panel sva-panel--half">
<h2><?php esc_html_e( 'Top Countries', 'stracini-visitor-analytics' ); ?></h2>
<table class="widefat striped ipquery-table">
<table class="widefat striped sva-table">
<thead>
<tr>
<th><?php esc_html_e( 'Country', 'stracini-visitor-analytics' ); ?></th>
Expand All @@ -100,22 +100,22 @@
</tr>
</thead>
<tbody>
<?php if ( empty( $ipquery_top_countries ) ) : ?>
<?php if ( empty( $sva_top_countries ) ) : ?>
<tr><td colspan="3"><?php esc_html_e( 'No data yet.', 'stracini-visitor-analytics' ); ?></td></tr>
<?php else : ?>
<?php foreach ( $ipquery_top_countries as $ipquery_row ) : ?>
<?php foreach ( $sva_top_countries as $sva_row ) : ?>
<tr>
<td>
<?php if ( $ipquery_row['country_code'] ) : ?>
<img src="https://flagcdn.com/16x12/<?php echo esc_attr( strtolower( $ipquery_row['country_code'] ) ); ?>.png"
<?php if ( $sva_row['country_code'] ) : ?>
<img src="https://flagcdn.com/16x12/<?php echo esc_attr( strtolower( $sva_row['country_code'] ) ); ?>.png"
width="16" height="12"
alt="<?php echo esc_attr( $ipquery_row['country_code'] ); ?>"
alt="<?php echo esc_attr( $sva_row['country_code'] ); ?>"
style="vertical-align:middle;margin-right:4px;">
<?php endif; ?>
<?php echo esc_html( $ipquery_row['country'] ?? $ipquery_row['country_code'] ?? '—' ); ?>
<?php echo esc_html( $sva_row['country'] ?? $sva_row['country_code'] ?? '—' ); ?>
</td>
<td><?php echo esc_html( number_format_i18n( (int) $ipquery_row['visits'] ) ); ?></td>
<td><?php echo $ipquery_total_visits > 0 ? esc_html( round( ( $ipquery_row['visits'] / $ipquery_total_visits ) * 100, 1 ) ) . '%' : '—'; ?></td>
<td><?php echo esc_html( number_format_i18n( (int) $sva_row['visits'] ) ); ?></td>
<td><?php echo $sva_total_visits > 0 ? esc_html( round( ( $sva_row['visits'] / $sva_total_visits ) * 100, 1 ) ) . '%' : '—'; ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
Expand All @@ -126,10 +126,10 @@
</div>

<!-- Cities table -->
<div class="ipquery-row">
<div class="ipquery-panel ipquery-panel--half">
<div class="sva-row">
<div class="sva-panel sva-panel--half">
<h2><?php esc_html_e( 'Top Cities', 'stracini-visitor-analytics' ); ?></h2>
<table class="widefat striped ipquery-table">
<table class="widefat striped sva-table">
<thead>
<tr>
<th><?php esc_html_e( 'City', 'stracini-visitor-analytics' ); ?></th>
Expand All @@ -139,23 +139,23 @@
</tr>
</thead>
<tbody>
<?php if ( empty( $ipquery_top_cities ) ) : ?>
<?php if ( empty( $sva_top_cities ) ) : ?>
<tr><td colspan="4"><?php esc_html_e( 'No data yet.', 'stracini-visitor-analytics' ); ?></td></tr>
<?php else : ?>
<?php foreach ( $ipquery_top_cities as $ipquery_row ) : ?>
<?php foreach ( $sva_top_cities as $sva_row ) : ?>
<tr>
<td><?php echo esc_html( $ipquery_row['city'] ); ?></td>
<td><?php echo esc_html( $sva_row['city'] ); ?></td>
<td>
<?php if ( $ipquery_row['country_code'] ) : ?>
<img src="https://flagcdn.com/16x12/<?php echo esc_attr( strtolower( $ipquery_row['country_code'] ) ); ?>.png"
<?php if ( $sva_row['country_code'] ) : ?>
<img src="https://flagcdn.com/16x12/<?php echo esc_attr( strtolower( $sva_row['country_code'] ) ); ?>.png"
width="16" height="12"
alt="<?php echo esc_attr( $ipquery_row['country_code'] ); ?>"
alt="<?php echo esc_attr( $sva_row['country_code'] ); ?>"
style="vertical-align:middle;margin-right:4px;">
<?php endif; ?>
<?php echo esc_html( $ipquery_row['country'] ?? $ipquery_row['country_code'] ?? '—' ); ?>
<?php echo esc_html( $sva_row['country'] ?? $sva_row['country_code'] ?? '—' ); ?>
</td>
<td><?php echo esc_html( number_format_i18n( (int) $ipquery_row['visits'] ) ); ?></td>
<td><?php echo $ipquery_total_visits > 0 ? esc_html( round( ( $ipquery_row['visits'] / $ipquery_total_visits ) * 100, 1 ) ) . '%' : '—'; ?></td>
<td><?php echo esc_html( number_format_i18n( (int) $sva_row['visits'] ) ); ?></td>
<td><?php echo $sva_total_visits > 0 ? esc_html( round( ( $sva_row['visits'] / $sva_total_visits ) * 100, 1 ) ) . '%' : '—'; ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
Expand All @@ -165,51 +165,51 @@
</div>

<!-- Risk detail cards -->
<div class="ipquery-row">
<div class="ipquery-panel">
<div class="sva-row">
<div class="sva-panel">
<h2><?php esc_html_e( 'Risk Details', 'stracini-visitor-analytics' ); ?></h2>
<div class="ipquery-risk-grid">
<div class="sva-risk-grid">
<?php
$ipquery_risk_items = array(
$sva_risk_items = array(
array(
'label' => __( '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 ) :
?>
<div class="ipquery-risk-item ipquery-risk-item--<?php echo esc_attr( $ipquery_item['class'] ); ?>">
<span class="dashicons dashicons-<?php echo esc_attr( $ipquery_item['icon'] ); ?>"></span>
<strong><?php echo esc_html( number_format_i18n( $ipquery_item['count'] ) ); ?></strong>
<small><?php echo esc_html( $ipquery_item['label'] ); ?></small>
<?php if ( $ipquery_unique_ips > 0 ) : ?>
<span class="ipquery-pct"><?php echo esc_html( round( ( $ipquery_item['count'] / $ipquery_unique_ips ) * 100, 1 ) ); ?>%</span>
<div class="sva-risk-item sva-risk-item--<?php echo esc_attr( $sva_item['class'] ); ?>">
<span class="dashicons dashicons-<?php echo esc_attr( $sva_item['icon'] ); ?>"></span>
<strong><?php echo esc_html( number_format_i18n( $sva_item['count'] ) ); ?></strong>
<small><?php echo esc_html( $sva_item['label'] ); ?></small>
<?php if ( $sva_unique_ips > 0 ) : ?>
<span class="sva-pct"><?php echo esc_html( round( ( $sva_item['count'] / $sva_unique_ips ) * 100, 1 ) ); ?>%</span>
<?php endif; ?>
</div>
<?php endforeach; ?>
Expand Down
Loading