'; return;
}
if (in_array($tab, array('settings', 'diagnostics'), true) && isset($_POST['wplocation_use_configured_db'])) {
check_admin_referer('wplocation_use_configured_db');
$source = wplocation_configured_database_path();
if (!is_string($source) || !is_file($source) || !is_readable($source)) { wp_die(esc_html__('The configured database is not readable.', 'wplocation')); }
try { $reader = new \MaxMind\Db\Reader($source); $reader->metadata(); $reader->close(); }
catch (Throwable $error) { wp_die(esc_html__('The configured database could not be read.', 'wplocation')); }
$lock = wplocation_acquire_database_lock();
if (!$lock) { wp_die(esc_html__('A database operation is already running. Try again later.', 'wplocation')); }
try {
$source_changed = !wplocation_source_matches($source);
if (!$source_changed) { wplocation_retire_selected_managed_database(); delete_option('wplocation_managed_database'); wplocation_purge_supported_cache(); }
} finally { wplocation_release_database_lock($lock); }
if ($source_changed) { wp_die(esc_html__('The database source changed. Reload settings and try again.', 'wplocation')); }
wplocation_record_event('database_selection', 'success');
echo '
WPLocation
' . esc_html__('Configured database selected. Disable automatic updates if you maintain it externally, and purge other page and CDN caches.', 'wplocation') . '
'; return;
}
if ($tab === 'settings' && isset($_POST['wplocation_save_maxmind_credentials'])) {
check_admin_referer('wplocation_save_maxmind_credentials');
if (defined('WPLOCATION_MAXMIND_ACCOUNT_ID') || defined('WPLOCATION_MAXMIND_LICENSE_KEY')) { wp_die(esc_html__('MaxMind credentials are controlled by wp-config.php on this site.', 'wplocation')); }
$account = isset($_POST['maxmind_account_id']) && is_string($_POST['maxmind_account_id']) ? trim(sanitize_text_field(wp_unslash($_POST['maxmind_account_id']))) : '';
$key = isset($_POST['maxmind_license_key']) && is_string($_POST['maxmind_license_key']) ? trim(sanitize_text_field(wp_unslash($_POST['maxmind_license_key']))) : '';
$clear = isset($_POST['clear_maxmind_credentials']);
if (!$clear && (!ctype_digit($account) || strlen($account) > 20 || ($key !== '' && (strlen($key) > 256 || !preg_match('/^[A-Za-z0-9_-]+$/', $key))))) { wp_die(esc_html__('Enter a numeric MaxMind account ID and a valid license key.', 'wplocation')); }
if (!$clear && $key === '' && !get_option('wplocation_maxmind_license_key')) { wp_die(esc_html__('Enter a MaxMind license key.', 'wplocation')); }
$lock = wplocation_acquire_database_lock();
if (!$lock) { wp_die(esc_html__('A database operation is already running. Try again later.', 'wplocation')); }
try {
if ($clear) {
delete_option('wplocation_maxmind_account_id');
delete_option('wplocation_maxmind_license_key');
update_option('wplocation_updates_enabled', 0, false);
wplocation_update_schedule();
} else {
update_option('wplocation_maxmind_account_id', $account, false);
if ($key !== '') { update_option('wplocation_maxmind_license_key', $key, false); }
}
} finally { wplocation_release_database_lock($lock); }
wplocation_record_event('maxmind_settings', 'success');
echo '
' . esc_html($clear ? __('Saved MaxMind credentials removed and updates disabled.', 'wplocation') : __('MaxMind account settings saved. The license key is never shown again.', 'wplocation')) . '
';
}
if ($tab === 'settings' && isset($_POST['wplocation_maxmind_initial'])) {
check_admin_referer('wplocation_maxmind_initial');
$directory = isset($_POST['maxmind_directory']) && is_string($_POST['maxmind_directory']) ? sanitize_text_field(wp_unslash($_POST['maxmind_directory'])) : '';
$result = isset($_POST['maxmind_download_consent']) ? wplocation_maxmind_install_initial($directory) : 'not_configured';
wplocation_record_event('maxmind_setup', $result);
$message = $result === 'success' ? __('GeoLite2 Country is now active. The previous file was retained and automatic updates remain off; enable them below after testing a lookup.', 'wplocation') : __('MaxMind setup did not complete. The previous source was retained. Check the account, entitlement, private directory and provider response.', 'wplocation');
echo '
';
if (!is_file(wplocation_database_path())) { echo '
' . esc_html__('No local country database is configured. Targeted content is hidden until location can be detected; see Diagnostics and check your cache.', 'wplocation') . '
' . esc_html__('Copy these examples into post or page content. A visitor whose country is unknown does not see targeted content.', 'wplocation') . '
';
echo '
' . esc_html__('Show content by country', 'wplocation') . '
' . esc_html__('Use country names or two-letter codes.', 'wplocation') . '
[wplocation_target country="US, PK"]Content for visitors in the US or Pakistan[/wplocation_target]
[wplocation_target exclude_country="US"]Content outside the US[/wplocation_target]
';
echo '
' . esc_html__('Display the detected country', 'wplocation') . '
' . esc_html__('Show the country name, code or flag emoji. Provide a fallback when no country can be detected. Flag appearance depends on the visitor’s device.', 'wplocation') . '
' . esc_html__('ACTIVE COUNTRY SOURCE', 'wplocation') . '
' . esc_html($current_label) . '
' . esc_html__('To switch sources, choose a setup path below. A successful switch disables the old automatic updater; enable updates for the new source after verifying a test lookup.', 'wplocation') . '
' . esc_html__('Choose a licensed country MMDB on this server. Keep it outside the public web directory. Visitor IP addresses stay on your server during lookups.', 'wplocation') . '
';
if (defined('WPLOCATION_GEOIP_DB_PATH')) {
echo '
' . esc_html__('The database path is managed in wp-config.php. Remove or change WPLOCATION_GEOIP_DB_PATH there before switching providers here.', 'wplocation') . '
' . esc_html__('The plugin is using a managed database copy. Older recorded copies are eligible for scheduled cleanup after two days; review provider deletion requirements and any other copies. Active file:', 'wplocation') . ' ' . esc_html(wplocation_active_database_path()) . '
' . esc_html__('Connect your own MaxMind account to download and update its licensed country database. Your account credentials go to MaxMind, then the signed file is downloaded from Cloudflare R2. Visitor IP addresses are not sent. WordPress cron requires site traffic or a server cron.', 'wplocation') . '
';
if (defined('WPLOCATION_MAXMIND_ACCOUNT_ID') || defined('WPLOCATION_MAXMIND_LICENSE_KEY')) {
echo '
' . esc_html__('This site supplies MaxMind credentials through wp-config.php. Those values take priority and cannot be changed here.', 'wplocation') . '
' . esc_html__('Download and select GeoLite2 Country', 'wplocation') . '
' . esc_html__('Save your MaxMind account above first. Choose an existing writable private directory outside the web root. This action downloads a current database using your account and keeps the previous source if it fails.', 'wplocation') . '
';
}
echo '';
if (get_option('wplocation_updates_enabled')) {
$status = get_option('wplocation_update_status', array());
if (is_array($status) && isset($status['result'])) { echo '
' . esc_html__('Free, Pro and add-ons are separate plugins. Check the WPLocation site for current availability, compatibility and pricing.', 'wplocation') . '
';
$offers = array(
array(__('Included in Free', 'wplocation'), __('Post, page and category country rules, shortcodes, a local country database and diagnostics.', 'wplocation'), wplocation_admin_url(array('tab' => 'settings'))),
array(__('WPLocation Pro', 'wplocation'), __('A separate licensed plugin for WooCommerce Markets, Geo Redirects, Forms & Campaigns and Geo Analytics. Free stays active alongside Pro.', 'wplocation'), 'https://wplocation.com/downloads/pro/'),
array(__('Optional add-ons', 'wplocation'), __('CloudFront Country Source, Affiliate Link Localization and Agency Toolkit are separate plugins with their own setup and eligibility.', 'wplocation'), 'https://wplocation.com/add-ons/'),
array(__('Future integrations', 'wplocation'), __('Additional integrations are described as planned on the website until released.', 'wplocation'), 'https://wplocation.com/add-ons/'),
);
echo '
';
}
/** A short health view; configuration forms live on Settings. */
function wplocation_render_diagnostics($ip_test_result) {
$path = wplocation_database_path();
$readable = is_string($path) && $path !== '' && is_file($path) && is_readable($path);
$type = ''; $built = 0; $error = '';
if ($readable) {
try {
$reader = new \MaxMind\Db\Reader($path); $metadata = $reader->metadata(); $reader->close();
$type = (string) $metadata->databaseType; $built = (int) $metadata->buildEpoch;
} catch (Throwable $exception) { $error = __('The database file cannot be read.', 'wplocation'); }
} else { $error = __('No readable country database is selected.', 'wplocation'); }
$stale = $built <= 0 || $built < time() - 30 * DAY_IN_SECONDS || $built > time() + DAY_IN_SECONDS;
$ready = !$error && $type === 'GeoLite2-Country' && !$stale;
echo '
' . esc_html__('SITE HEALTH', 'wplocation') . '
' . esc_html__('Diagnostics', 'wplocation') . '
' . esc_html__('Check whether country lookups can work, then test an address. Change providers and update settings on the Settings page.', 'wplocation') . '
' . esc_html__('Test an IP address', 'wplocation') . '
' . esc_html__('Look up an IPv4 or IPv6 address using the local database. The test address is not saved or sent to a lookup provider.', 'wplocation') . '
' . esc_html__('Purge page and CDN caches after database, rule or plugin changes. A cache can serve a response before WordPress runs.', 'wplocation') . '
' . esc_html__('Test a targeted URL from different visitor locations. IP location is approximate and cannot protect private content.', 'wplocation') . '
';
}
/** Show setup state without sending an IP address to an external service. */
function wplocation_render_overview() {
$state = __('Not configured', 'wplocation'); $detail = __('Choose a local country database to get started.', 'wplocation'); $healthy = false;
if (is_string(wplocation_database_path()) && is_file(wplocation_database_path()) && is_readable(wplocation_database_path())) {
try {
$reader = new \MaxMind\Db\Reader(wplocation_database_path()); $meta = $reader->metadata(); $reader->close();
$epoch = (int) $meta->buildEpoch;
if ($meta->databaseType !== 'GeoLite2-Country') {
$state = __('Action needed', 'wplocation'); $detail = __('Choose a GeoLite2 Country database.', 'wplocation');
} elseif ($epoch <= 0 || $epoch < time() - 30 * DAY_IN_SECONDS || $epoch > time() + DAY_IN_SECONDS) {
$state = __('Check data freshness', 'wplocation'); $detail = __('Check the database date and the provider’s update requirements.', 'wplocation');
} else {
$state = __('Database readable', 'wplocation'); $detail = __('Your local database is configured. Check a visitor country in Diagnostics.', 'wplocation'); $healthy = true;
}
} catch (Throwable $error) { $state = __('Cannot read database', 'wplocation'); $detail = __('Check the database file and permissions.', 'wplocation'); }
}
$updating = (bool) get_option('wplocation_updates_enabled');
echo '
'; }
/* translators: %s: list of selected countries. */
$include_format = __('Only visitors in %s can see this content.', 'wplocation');
/* translators: %s: list of selected countries. */
$exclude_format = __('Visitors in %s cannot see this content.', 'wplocation');
/* translators: %s: country name. */
$remove_format = __('Remove %s', 'wplocation');
/* translators: %s: number of countries currently displayed. */
$match_format = __('%s country shown', 'wplocation');
/* translators: %s: number of countries currently displayed. */
$matches_format = __('%s countries shown', 'wplocation');
echo '
' . esc_html__('Choose a recognized country.', 'wplocation') . '
'; }
}
$preview_names = implode(', ', array_slice($countries, 0, 3));
if (count($countries) > 3) { $preview_names .= ' +' . (count($countries) - 3); }
$initial_summary = $action === 'all' ? __('Everyone can see this content, including visitors whose country is unknown.', 'wplocation') : (!$countries ? __('Choose at least one country to finish this audience.', 'wplocation') : sprintf($action === 'exclude' ? $exclude_format : $include_format, $preview_names));
echo '
';
}
/** Alert administrators when a previously working source disappears. */
function wplocation_missing_database_notice() {
if (!current_user_can('manage_options') || (is_string(wplocation_database_path()) && is_file(wplocation_database_path()) && is_readable(wplocation_database_path()))) { return; }
echo '
' . esc_html__('WPLocation cannot read a country database. Content with country rules may be hidden until the database is configured. Purge page and CDN caches after setup.', 'wplocation') . ' ' . esc_html__('Open diagnostics', 'wplocation') . '