Fix Missing Or Wrong Country Codes
Applies to SlimStat 5.5.0 · checked
SlimStat records a country only when the active geolocation provider resolves the visitor IP during the tracking request, at src/Tracker/Processor.php line 358. A blank country usually means the .mmdb file in wp-content/uploads/wp-slimstat/ was never downloaded, because a missing file returns null silently and logs no error. Cloudflare Header needs no database at all.
Check These Six Causes In Order
Six conditions cover nearly every country problem: the Geolocation Provider setting, the .mmdb file on disk, Cloudflare Header without a CF-Ray, GDPR Compliance Mode withholding consent, a proxy replacing the visitor IP, and MaxMind’s registered-country fallback. Work down the table in order, because a missing database masks every cause below.
| Cause | Symptom in SlimStat reports | Where to check |
|---|---|---|
| Geolocation Provider set to Disabled | Country blank on every row | SlimStat > Settings > Tracker |
| The .mmdb file was never downloaded | Country blank, GeoIP error still “So far so good.” | SlimStat > Settings > Maintenance |
| Cloudflare Header without a CF-Ray header | Country blank on every row | Request headers reaching the origin |
| GDPR Compliance Mode, consent not granted | Country blank until the visitor accepts | SlimStat > Settings > Tracker |
| Proxy or CDN replaces the visitor IP | One wrong country across all traffic | Access Log row detail, IP line |
| MaxMind registered-country fallback | Wrong but plausible country | MaxmindGeoIPProvider.php line 56 |
Confirm The .mmdb File Was Actually Downloaded
The Maintenance tab’s “GeoIP Database Updated” row reads Never until a download succeeds, which is the fastest single check. DB-IP stores dbip-city-lite.mmdb; MaxMind stores GeoLite2-Country.mmdb at Country precision and GeoLite2-City.mmdb at City precision. A missing file makes the lookup return null, so no GeoIP error is ever recorded.
- Open SlimStat > Settings > Maintenance and read the “GeoIP Database Updated” row.
- Treat a value of Never as the diagnosis: no database has ever been fetched.
- Open SlimStat > Settings > Tracker and confirm Geolocation Provider is not set to Disabled.
- Click Check Database, which under DB-IP or MaxMind answers “GeoIP Database is present and ready.” or “GeoIP Database not found.”
- Click Update Database to fetch a copy now instead of waiting for the weekly cron event.
- Re-read the “GeoIP Database Error” row for a specific failure, such as an invalid MaxMind license key.
MaxMind names its file after the precision selected, so flipping Geolocation Precision between Country and City changes the filename the tracker opens and requires a fresh download. DB-IP City Lite uses dbip-city-lite.mmdb at both settings. Provider choice and license keys are covered in setting up visitor geolocation.
Anonymize IP And Hash IP Do Not Break The Lookup
Anonymize IP Addresses and Hash IP Addresses, both Data Protection toggles on the Tracker tab, leave the pageview country lookup intact. SlimStat copies the raw visitor IP into a separate variable at src/Tracker/Processor.php line 162, then anonymises and hashes the stored IP at line 191, so the provider still receives the untouched address.
GDPR Compliance Mode is the setting that does gate the lookup. With gdpr_enabled on and consent not yet granted, the PII check returns false and Processor.php skips the whole geolocation block, so countries appear only once a visitor accepts. Hash IP Addresses matters in one narrower place: on a consent upgrade, SlimStat re-runs the lookup for the already-written row only when Hash IP Addresses is off, at Processor.php line 634.
A Proxy Or CDN Can Hand PHP The Wrong IP
REMOTE_ADDR behind a load balancer or CDN often carries the proxy address, which produces one identical wrong country across all traffic. SlimStat therefore scans nine headers at src/Tracker/Utils.php line 432, starting with X-Forwarded-For, and stores the first different valid address as other_ip, which the geolocation step prefers over the public IP.
Cloudflare is handled separately: CF-Connecting-IP is used for geolocation only when the CF-Ray header is present on the same request, so a spoofed CF-Connecting-IP on an unproxied origin is ignored (Utils.php line 455). The Cloudflare Header provider enforces the same CF-Ray requirement and returns nothing without that header.
With Show Hostnames off, each Access Log row detail prints the stored pair as “IP: public / originating”, so a single repeated address there confirms the proxy case. When no header carries the visitor address, correct the pair with the slimstat_filter_ip_address filter at Utils.php line 446, which receives the two-element IP array.
Existing Rows Keep The Country They Were Written With
Downloading the .mmdb file today fixes pageviews recorded from that moment on, and nothing else. SlimStat writes the resolved code into the country column of wp_slim_stats as a lowercase two-letter value, and no cron event, migration, or Maintenance action re-runs the lookup across stored rows.
Rows written before the fix keep an empty country, which the label table renders as Unknown at languages/index.php line 14. The code xx is never stored: Processor.php line 371 rejects that placeholder before writing, so an Unknown row in Top Countries means the column is empty. Also confirm the Countries box under SlimStat > Settings > Exclusions is empty, because a code listed there discards the entire pageview with tracker error 311, not just the country.
The Filter To Use
SlimStat applies exactly one filter to the IP used for geolocation, slimstat_filter_ip_address. The older slimstat_get_country filter name appears nowhere in the source of the free plugin or of Pro, so a callback attached to that name never runs and cannot correct a stored code.
To override a country after resolution, hook slimstat_filter_pageview_stat at src/Tracker/Processor.php line 431, which receives the pageview array immediately before the row is written; the filter reference lists its arguments. To share one .mmdb file across a network, use slimstat_maxmind_path, applied to the upload directory at wp-slimstat.php line 408.