File: /home/teamadsc/public_html/wp-content/plugins/visitors/functions.php
<?php
function ahcpro_check_settings()
{
global $wpdb;
$table_exist = ahcpro_check_table_exists('ahc_settings');
if ($table_exist) {
if (!ahcpro_check_table_column_exists('ahc_settings', 'site_id')) {
ahcpro_multisite_init();
}
$result = $wpdb->get_results("SELECT count(*) as cnt FROM ahc_settings where site_id = " . get_current_blog_id(), OBJECT);
if ($result !== false) {
return $result[0]->cnt;
}
}
return 0;
}
function ahcpro_remove_dokan_js_files()
{
if (isset($_GET['page']) && $_GET['page'] == 'ahc_hits_counter_menu_pro') {
wp_dequeue_script('dokan-tinymce-plugin');
wp_deregister_script('dokan-tinymce-plugin');
wp_dequeue_script('dokan-moment');
wp_deregister_script('dokan-moment');
wp_dequeue_script('dokan-chart');
wp_deregister_script('dokan-chart');
wp_dequeue_script('vue-vendor');
wp_deregister_script('vue-vendor');
wp_dequeue_script('dokan-promo-notice-js');
wp_deregister_script('dokan-promo-notice-js');
wp_dequeue_script('dps-custom-admin-js');
wp_deregister_script('dps-custom-admin-js');
}
}
add_action('admin_print_scripts', 'ahcpro_remove_dokan_js_files', 1);
add_shortcode('ahc_stats_widget', 'ahcpro_stats_widget_func');
//[ahc_stats_widget title="" fontsize="16" fonttype="" display_today_visitors=true display_today_pageviwes=true display_total_visitors=true display_total_pageviwes=true ]
function ahcpro_stats_widget_func($instance = [])
{
$args = shortcode_atts(array(
'fontsize' => '14',
'title' => '',
'fonttype' => '',
'display_today_visitors' => "true",
'display_today_pageviwes' => "true",
'display_total_visitors' => "true",
'display_total_pageviwes' => "true"
), $instance);
$ret = '';
$ahc_sum_stats = ahcpro_get_summary_statistics();
$ret .= isset($args['title']) ? '<h3 class="ahc_stats_widget_title">' . esc_html($args['title']) . '</h3>' : '';
// This is where you run the code and display the output
$ret .= '<ul class="ahc_stats_widget" style="list-style:none; font-family: ' . esc_attr($args['fonttype']) . ' !important; font-size:' . esc_attr($args['fontsize']) . 'px !important">';
if ($args['display_today_visitors'] != 'false' && $args['display_today_visitors'] != false) {
$ret .= '<li><b>' . __("Today's visitors: ", 'visitors-traffic-real-time-statistics') . '</b><span>' . ahc_pro_NumFormat(intval($ahc_sum_stats['today']['visitors'])) . '</span></li>';
}
if ($args['display_today_pageviwes'] != 'false' && $args['display_today_pageviwes'] != false) {
$ret .= '<li><b>' . __("Today's page views: ", 'visitors-traffic-real-time-statistics') . ' </b><span>' . ahc_pro_NumFormat(intval($ahc_sum_stats['today']['visits'])) . '</span></li>';
}
if ($args['display_total_visitors'] != 'false' && $args['display_total_visitors'] != false) {
$ret .= '<li><b>' . __("Total visitors: ", 'visitors-traffic-real-time-statistics') . ' </b><span>' . ahc_pro_NumFormat(intval($ahc_sum_stats['total']['visitors'])) . '</span></li>';
}
if ($args['display_total_pageviwes'] != 'false' && $args['display_total_visitors'] != false) {
$ret .= '<li><b>' . __("Total page views: ", 'visitors-traffic-real-time-statistics') . ' </b><span>' . ahc_pro_NumFormat(intval($ahc_sum_stats['total']['visits'])) . '</span></li>';
}
$ret .= '</ul>';
return $ret;
}
add_shortcode('ahc_today_visitors', 'ahcpro_today_visitors_func');
function ahcpro_today_visitors_func()
{
$ahc_sum_stats = ahcpro_get_visitors_visits_in_period('today');
return ahc_pro_NumFormat(intval($ahc_sum_stats['visitors']));
}
add_shortcode('ahc_today_visits', 'ahcpro_today_visits_func');
function ahcpro_today_visits_func()
{
$ahc_sum_stats = ahcpro_get_visitors_visits_in_period('today');
return ahc_pro_NumFormat(intval($ahc_sum_stats['visits']));
}
add_shortcode('ahc_total_visitors', 'ahcpro_total_visitors_func');
function ahcpro_total_visitors_func()
{
$ahc_sum_stats = ahcpro_get_visitors_visits_in_period('total');
return ahc_pro_NumFormat(intval($ahc_sum_stats['visitors']));
}
add_shortcode('ahc_total_visits', 'ahcpro_total_visits_func');
function ahcpro_total_visits_func()
{
$ahc_sum_stats = ahcpro_get_visitors_visits_in_period('total');
return ahc_pro_NumFormat(intval($ahc_sum_stats['visits']));
}
add_shortcode('ahc_yesterday_total_visits', 'ahcpro_yesterday_total_visits_func');
function ahcpro_yesterday_total_visits_func()
{
$ahc_sum_stats = ahcpro_get_visitors_visits_in_period('yesterday');
return ahc_pro_NumFormat(intval($ahc_sum_stats['visits']));
}
add_shortcode('ahc_yesterday_total_visitors', 'ahcpro_yesterday_total_visitors_func');
function ahcpro_yesterday_total_visitors_func()
{
$ahc_sum_stats = ahcpro_get_visitors_visits_in_period('yesterday');
return ahc_pro_NumFormat(intval($ahc_sum_stats['visitors']));
}
/**
* Hash IP
*
*/
function ahcfpro_haship($ip)
{
if ($ip != '') {
$ip = explode('.', $ip);
return $ip[0] . "." . $ip[1] . "." . $ip[2] . ".***";
} else {
return '';
}
}
function vtrts_pro_top_bar_enqueue_style()
{
wp_enqueue_style('admin-bar');
$custom_css = '
.canvasjs-chart-credit{
display: none !important;
}
#vtrtsProChart canvas {
border-radius: 6px;
}
.vtrts-pro-adminbar-weekly-title {
font-weight: bold;
font-size: 14px;
color: #fff;
margin-bottom: 6px;
}
#wpadminbar #wp-admin-bar-vtrts_pro_top_button .ab-icon:before {
content: "\f185";
color: #1DAE22;
top: 3px;
}
#wp-admin-bar-vtrts_pro_top_button .ab-item {
min-width: 180px;
}
.vtrts-pro-adminbar-dropdown {
min-width: 340px;
padding: 18px 18px 12px 18px;
background: #23282d;
color: #fff;
border-radius: 8px;
box-shadow: 0 4px 24px rgba(0,0,0,0.15);
margin-top: 10px;
}
.vtrts-pro-adminbar-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 18px 18px; /* row-gap column-gap */
margin-bottom: 18px;
}
.vtrts-pro-adminbar-card {
background: #2c3338;
border-radius: 8px;
padding: 18px 18px 12px 18px;
box-shadow: 0 2px 8px rgba(0,0,0,0.07);
display: flex;
flex-direction: column;
align-items: flex-start;
}
/* Extra margin for the right column */
.vtrts-pro-adminbar-card:nth-child(2),
.vtrts-pro-adminbar-card:nth-child(4) {
margin-left: 10px !important;
padding-left: 10px !important;
margin-right: 10px !important;
padding-right : 10px !important;
margin-top: 10px !important;
}
.vtrts-pro-adminbar-card:nth-child(1),
.vtrts-pro-adminbar-card:nth-child(3) {
margin-left: 10px !important;
padding-left: 10px !important;
margin-top: 10px !important;
}
/* Extra margin for the bottom row */
.vtrts-pro-adminbar-card:nth-child(3),
.vtrts-pro-adminbar-card:nth-child(4) {
margin-top: 6px !important;
padding-top: 6px !important;
margin-top: 10px !important;
}
.vtrts-pro-adminbar-card-title {
font-size: 14px;
font-weight: 800;
margin-bottom: 6px;
color: #fff;
}
.vtrts-pro-adminbar-card-value {
font-size: 22px;
font-weight: bold;
color: #1DAE22;
margin-bottom: 4px;
}
.vtrts-pro-adminbar-card-sub {
font-size: 12px;
color: #aaa;
}
.vtrts-pro-adminbar-btn-wrap {
text-align: center;
margin-top: 8px;
}
#wp-admin-bar-vtrts_pro_top_button .ab-item{
min-width: 80px !important;
padding: 0px !important;
.vtrts-pro-adminbar-btn {
display: inline-block;
background: #1DAE22;
color: #fff !important;
font-weight: bold;
padding: 8px 28px;
border-radius: 6px;
text-decoration: none;
font-size: 15px;
transition: background 0.2s;
margin-top: 8px;
}
.vtrts-pro-adminbar-btn:hover {
background: #15991b;
color: #fff !important;
}
.vtrts-pro-adminbar-dropdown-wrap { min-width: 0; padding: 0; }
#wpadminbar #wp-admin-bar-vtrts_pro_top_button .vtrts-pro-adminbar-dropdown { display: none; position: absolute; left: 0; top: 100%; z-index: 99999; }
#wpadminbar #wp-admin-bar-vtrts_pro_top_button:hover .vtrts-pro-adminbar-dropdown { display: block; }
.ab-empty-item #wp-admin-bar-vtrts_pro_top_button-default .ab-empty-item{
height:0px !important;
padding :0px !important;
}
#wpadminbar .quicklinks .ab-empty-item{
padding:0px !important;
}
.vtrts-pro-adminbar-dropdown {
min-width: 340px;
padding: 18px 18px 12px 18px;
background: #23282d;
color: #fff;
border-radius: 12px; /* more rounded */
box-shadow: 0 8px 32px rgba(0,0,0,0.25); /* deeper shadow */
margin-top: 10px;
}
.vtrts-pro-adminbar-btn-wrap {
text-align: center;
margin-top: 18px; /* more space above */
}
.vtrts-pro-adminbar-btn {
display: inline-block;
background: #1DAE22;
color: #fff !important;
font-weight: bold;
padding: 5px 22px;
border-radius: 8px;
text-decoration: none;
font-size: 17px;
transition: background 0.2s, box-shadow 0.2s;
margin-top: 8px;
box-shadow: 0 2px 8px rgba(29,174,34,0.15);
text-align: center;
line-height: 1.6;
}
.vtrts-pro-adminbar-btn:hover {
background: #15991b;
color: #fff !important;
box-shadow: 0 4px 16px rgba(29,174,34,0.25);
}
';
wp_add_inline_style('admin-bar', $custom_css);
}
function ahcpro_get_online_users()
{
global $wpdb;
$sql = "SELECT DISTINCT hit_ip_address FROM `ahc_online_users`
WHERE `site_id` = '" . get_current_blog_id() . "'
AND `date` >= DATE_ADD('" . ahcpro_localtime("Y-m-d H:i:s") . "', INTERVAL -2 MINUTE)";
$result = $wpdb->get_results($sql, OBJECT);
return ($result !== false) ? count($result) : 0;
}
/**
* Get unique visitor counts by day range
*
* @param string $start_date Start date in Y-m-d format
* @param string $end_date End date in Y-m-d format
* @return array Array of visitor counts by day
*/
function ahcpro_get_visitors_by_day_range($start_date, $end_date)
{
global $wpdb;
$results = $wpdb->get_results(
$wpdb->prepare("
SELECT DATE(`vst_date`) as day, SUM(`vst_visitors`) as visitors
FROM `ahc_visitors`
WHERE DATE(`vst_date`) BETWEEN %s AND %s
AND `site_id` = %d
GROUP BY day
ORDER BY day ASC
", $start_date, $end_date, get_current_blog_id()),
ARRAY_A
);
// Debug log
foreach ($results as $r) {
error_log("VISITORS - {$r['day']}: {$r['visitors']}");
}
return $results;
}
/**
* Get both visits and unique visitors by day range with proper alignment
*
* @param string $start_date Start date in Y-m-d format
* @param string $end_date End date in Y-m-d format
* @return array Array with dates, visitors, and visits
*/
function ahcpro_get_visits_and_visitors_by_day_range($start_date, $end_date)
{
global $wpdb;
// Get timezone settings (same as summary stats function)
$custom_timezone_offset = ahcpro_get_current_timezone_offset();
// Step 1: Initialize day map
$day_map = [];
$current = new DateTime($start_date);
$end = new DateTime($end_date);
$end->modify('+1 day'); // Include end date
while ($current < $end) {
$day_key = $current->format('Y-m-d');
$day_map[$day_key] = [
'day' => $day_key,
'visitors' => 0,
'visits' => 0
];
$current->modify('+1 day');
}
// Step 2: Query actual data from `ahc_visitors` with timezone conversion
$results = $wpdb->get_results(
$wpdb->prepare("
SELECT DATE(CONVERT_TZ(`vst_date`, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) as day,
SUM(`vst_visitors`) as visitors,
SUM(`vst_visits`) as visits
FROM `ahc_visitors`
WHERE DATE(CONVERT_TZ(`vst_date`, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) BETWEEN %s AND %s
AND `site_id` = %d
GROUP BY day
ORDER BY day ASC
", $start_date, $end_date, get_current_blog_id()),
ARRAY_A
);
// Debug log to verify data consistency
foreach ($results as $r) {
error_log("CHART DATA - {$r['day']}: visitors={$r['visitors']}, visits={$r['visits']}");
}
// Step 3: Fill day map with real data
foreach ($results as $row) {
if (isset($day_map[$row['day']])) {
$day_map[$row['day']]['visitors'] = (int)$row['visitors'];
$day_map[$row['day']]['visits'] = (int)$row['visits'];
}
}
// Step 4: Prepare chart arrays
$dates = [];
$visitors = [];
$visits = [];
foreach ($day_map as $day_data) {
$dates[] = date('d/m', strtotime($day_data['day']));
$visitors[] = $day_data['visitors'];
$visits[] = $day_data['visits'];
}
return [
'dates' => $dates,
'visitors' => $visitors,
'visits' => $visits
];
}
function enqueue_canvasjs()
{
wp_enqueue_script('canvasjs', 'https://cdn.canvasjs.com/canvasjs.min.js', array(), null, true);
}
function vtrts_pro_add_items($admin_bar)
{
if (!current_user_can('manage_options')) {
return;
}
$ahc_sum_stat = ahcpro_get_summary_statistics();
// Build chart data using the improved function
$chart_data = ahcpro_get_visits_and_visitors_by_day_range(
date('Y-m-d', strtotime('-6 days')),
date('Y-m-d')
);
// Store data for use in footer
$GLOBALS['vtrts_chart_data'] = [
'labels' => $chart_data['dates'],
'data' => $chart_data['visitors'] // Use visitors instead of visits
];
// Rest of the function remains the same...
$chart_html = '<div class="vtrts-pro-adminbar-weekly">'
. '<div class="vtrts-pro-adminbar-weekly-title">' . __('Visitors - Last 7 Days', 'visitors-traffic-real-time-statistics-pro') . '</div>'
. '<div id="vtrtsProChart" style="height: 200px; width: 320px; background-color: #23282d; border-radius: 6px;"></div>'
. '</div>';
// Build dropdown HTML
$dropdown_html = '<div class="vtrts-pro-adminbar-dropdown">'
. '<div class="vtrts-pro-adminbar-grid">'
. '<div class="vtrts-pro-adminbar-card">'
. '<div class="vtrts-pro-adminbar-card-title">' . __('Visitors Today', 'visitors-traffic-real-time-statistics-pro') . '</div>'
. '<div class="vtrts-pro-adminbar-card-value">' . ahc_pro_NumFormat($ahc_sum_stat['today']['visitors']) . '</div>'
. '<div class="vtrts-pro-adminbar-card-sub">' . sprintf(__('%s Visitors yesterday', 'visitors-traffic-real-time-statistics-pro'), ahc_pro_NumFormat($ahc_sum_stat['yesterday']['visitors'])) . '</div>'
. '</div>'
. '<div class="vtrts-pro-adminbar-card">'
. '<div class="vtrts-pro-adminbar-card-title">' . __('Views Today', 'visitors-traffic-real-time-statistics-pro') . '</div>'
. '<div class="vtrts-pro-adminbar-card-value">' . ahc_pro_NumFormat($ahc_sum_stat['today']['visits']) . '</div>'
. '<div class="vtrts-pro-adminbar-card-sub">' . sprintf(__('%s views yesterday', 'visitors-traffic-real-time-statistics-pro'), ahc_pro_NumFormat($ahc_sum_stat['yesterday']['visits'])) . '</div>'
. '</div>'
. '<div class="vtrts-pro-adminbar-card">'
. '<div class="vtrts-pro-adminbar-card-title">' . __('Total Visitors', 'visitors-traffic-real-time-statistics-pro') . '</div>'
. '<div class="vtrts-pro-adminbar-card-value">' . ahc_pro_NumFormat($ahc_sum_stat['total']['visitors']) . '</div>'
. '<div class="vtrts-pro-adminbar-card-sub">' . __('All Time', 'visitors-traffic-real-time-statistics-pro') . '</div>'
. '</div>'
. '<div class="vtrts-pro-adminbar-card">'
. '<div class="vtrts-pro-adminbar-card-title">' . __('Total Views', 'visitors-traffic-real-time-statistics-pro') . '</div>'
. '<div class="vtrts-pro-adminbar-card-value">' . ahc_pro_NumFormat($ahc_sum_stat['total']['visits']) . '</div>'
. '<div class="vtrts-pro-adminbar-card-sub">' . __('All Time', 'visitors-traffic-real-time-statistics-pro') . '</div>'
. '</div>'
. '</div>' . $chart_html
. '<div class="vtrts-pro-adminbar-btn-wrap">'
. '<a href="' . esc_url(admin_url('admin.php?page=ahc_hits_counter_menu_pro')) . '" class="vtrts-pro-adminbar-btn">'
. __('Explore Details', 'visitors-traffic-real-time-statistics-pro') . '</a>'
. '</div>'
. '</div>';
$menu_title = '<span class="ab-icon"></span> ';
$menu_title .= __('Online: ', 'visitors-traffic-real-time-statistics-pro');
$menu_title .= '<span id="up-down_adminbar"></span><span id="onlinecounter_adminbar">0</span>';
$admin_bar->add_menu(array(
'id' => 'vtrts_pro_top_button',
'title' => $menu_title,
'href' => false,
'meta' => array(
'title' => __('Visitor Traffic Real Time Statistics PRO', 'visitors-traffic-real-time-statistics-pro'),
'class' => 'vtrts-pro-admin-bar',
)
));
$admin_bar->add_menu(array(
'id' => 'vtrts_pro_top_button_dropdown',
'parent' => 'vtrts_pro_top_button',
'title' => $dropdown_html,
'href' => false,
'meta' => array('class' => 'vtrts-pro-adminbar-dropdown-wrap')
));
}
function vtrts_pro_adminbar_chart()
{
if (!isset($GLOBALS['vtrts_chart_data'])) return;
$chart_data = $GLOBALS['vtrts_chart_data'];
$data_points = [];
// Ensure data points are properly created for all days
foreach ($chart_data['labels'] as $index => $label) {
$data_points[] = [
'label' => $label,
'y' => isset($chart_data['data'][$index]) ? (int)$chart_data['data'][$index] : 0
];
}
?>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function() {
// Get data points from PHP
const dataPoints = <?php echo json_encode($data_points, JSON_NUMERIC_CHECK); ?>;
// Calculate dynamic Y-axis settings based on data
function calculateYAxisSettings(dataPoints) {
if (!dataPoints || dataPoints.length === 0) {
return {
interval: 1,
maximum: 10
};
}
// Find min and max values
const values = dataPoints.map(point => point.y);
const maxValue = Math.max(...values);
// If all values are the same or very small
if (maxValue <= 1) {
return {
interval: 1,
maximum: null
};
}
// بما أن الشارت يستخدم includeZero:true فالنطاق الفعلي هو [0, maxValue]
// نحسب الـ interval على أساس maxValue لضمان عدد معقول من الـ labels (5-8 labels)
let interval;
if (maxValue <= 10) {
interval = 1; // 1, 2, 3, ..., 10
} else if (maxValue <= 20) {
interval = 5; // 5, 10, 15, 20
} else if (maxValue <= 50) {
interval = 10; // 10, 20, 30, 40, 50
} else if (maxValue <= 100) {
interval = 20; // 20, 40, 60, 80, 100
} else if (maxValue <= 200) {
interval = 50; // 50, 100, 150, 200
} else if (maxValue <= 500) {
interval = 100; // 100, 200, 300, 400, 500
} else if (maxValue <= 1000) {
interval = 200; // 200, 400, 600, 800, 1000
} else if (maxValue <= 5000) {
interval = 1000; // 1K, 2K, 3K, 4K, 5K
} else if (maxValue <= 10000) {
interval = 2000; // 2K, 4K, 6K, 8K, 10K
} else if (maxValue <= 50000) {
interval = 10000; // 10K, 20K, 30K, 40K, 50K
} else if (maxValue <= 100000) {
interval = 20000; // 20K, 40K, 60K, 80K, 100K
} else {
// للأرقام الضخمة: قسم إلى ~5 intervals
const magnitude = Math.pow(10, Math.floor(Math.log10(maxValue)) - 1);
interval = Math.ceil(maxValue / 5 / magnitude) * magnitude;
}
return {
interval: interval,
maximum: null // Let CanvasJS decide the maximum
};
}
const yAxisSettings = calculateYAxisSettings(dataPoints);
const chart = new CanvasJS.Chart("vtrtsProChart", {
backgroundColor: "#23282d",
animationEnabled: true,
width: 320,
height: 200,
axisX: {
labelFontColor: "#ccc",
lineColor: "#444",
tickColor: "#444"
},
axisY: {
labelFontColor: "#ccc",
lineColor: "#444",
tickColor: "#444",
gridColor: "#444",
includeZero: true,
interval: yAxisSettings.interval,
maximum: yAxisSettings.maximum,
// Ensure labels are always whole numbers with thousands separator
labelFormatter: function(e) {
return Math.round(e.value).toLocaleString('en-US');
}
},
legend: {
fontColor: "#fff",
fontSize: 12,
horizontalAlign: "center",
verticalAlign: "bottom",
dockInsidePlotArea: false
},
data: [{
type: "line",
name: "Visitors",
showInLegend: true,
markerType: "circle",
markerSize: 8,
markerColor: "#1DAE22",
color: "#1DAE22",
lineThickness: 2,
dataPoints: dataPoints
}]
});
chart.render();
});
</script>
<?php
}
/**
* Called when plugin is activated or upgraded
*
* @uses add_option()
* @uses get_option()
*
* @return void
*/
function ahcpro_localtime($format = 'Y-m-d H:i:s')
{
$timezone_name = ahcpro_get_timezone_string();
try {
$timezone = new DateTimeZone($timezone_name);
$datetime = new DateTime('now', $timezone);
return $datetime->format($format);
} catch (Exception $e) {
error_log('ahcpro_localtime error: ' . $e->getMessage());
$datetime = new DateTime('now', new DateTimeZone('UTC'));
return $datetime->format($format);
}
}
function ahcpro_getVisitsTime($site_id = '')
{
if ($site_id == '') {
$site_id = get_current_blog_id();
}
global $wpdb;
$result = $wpdb->get_results("SELECT COUNT( `vtm_id` ) cnt FROM ahc_visits_time where site_id = " . $site_id, OBJECT);
if ($result !== false) {
return $result[0]->cnt;
}
return false;
}
function ahcpro_google_map($map_option)
{
ahcpro_include_scripts();
global $wpdb;
$ahcpro_get_save_settings = ahcpro_get_save_settings();
$map_status = isset($ahcpro_get_save_settings[0]->set_google_map) ? $ahcpro_get_save_settings[0]->set_google_map : '';
if ($map_status == 'online') {
$ctrArr = ahcpro_get_online_visitors_for_map();
} else if ($map_status == 'all') { // top 10 coutries
$ctrArr = ahcpro_get_all_visitors_for_map(' limit 300');
} else if ($map_status == 'top10') { // top 10 coutries
$ctrArr = ahcpro_get_all_visitors_for_map(' limit 10');
} else if ($map_status == 'this_month') // this month visitors
{
$ctrArr = ahcpro_get_today_visitors_for_map('this_month'); // today visitors
} else if ($map_status == 'past_month') // this month visitors
{
$ctrArr = ahcpro_get_today_visitors_for_map('past_month'); // today visitors
} else {
$ctrArr = ahcpro_get_today_visitors_for_map(); // default : today visitors
}
$ret = '<div id="OSMap" style="width: 100%; height:540px;"></div>
<script language="javascript" type="text/javascript">
jQuery(document).ready(function(){
var map = L.map( "OSMap", {
center: [34.307144, -8.789062],
minZoom: 2,
zoom: 2
});
L.tileLayer( "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: "© <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a>",
subdomains: ["a","b","c"]
}).addTo( map );
';
$counter = 1;
if ($ctrArr['success'] && isset($ctrArr['data']) && count($ctrArr['data']) > 0) {
foreach ($ctrArr['data'] as $vc) {
$info = '<div style="overflow: auto;">';
$info .= '<div class="countryMarker"><img src="' .
plugins_url('/images/flags/' . strtolower($vc['ctr_internet_code']) . '.png', AHCPRO_PLUGIN_MAIN_FILE) .
'" border="0" width="20" height="16" onerror="imgFlagError(this)" /></span><span class="countryName">' . str_replace("'", "", $vc['ctr_name']) . ' <span class="countryName">(' . str_replace("'", "", $vc['visitors']) . ')</span></div>';
$info .= '</div>';
$ret .= 'L.marker( [' . $vc['ctr_latitude'] . ', ' . $vc['ctr_longitude'] . '] )
.bindPopup( \'' . $info . '\').addTo( map ).openPopup();';
$counter++;
}
}
$ret .= '
});
</script>';
return $ret;
}
/**
* change plugin settings
* @return void
*/
function ahcpro_savesettings()
{
global $wpdb;
$ahcpro_hide_top_bar_icon = isset($_POST['ahcpro_hide_top_bar_icon']) ? intval($_POST['ahcpro_hide_top_bar_icon']) : '0';
$ahcpro_haships = isset($_POST['ahcpro_haships']) ? intval($_POST['ahcpro_haships']) : '0';
$set_hits_days = isset($_POST['set_hits_days']) ? intval($_POST['set_hits_days']) : 14;
$set_ajax_check = isset($_POST['set_ajax_check']) ? intval($_POST['set_ajax_check']) : 14;
$set_ips = esc_html($_POST['set_ips']);
$set_google_map = $_POST['set_google_map'];
$custom_timezone_offset = $_POST['set_custom_timezone'];
if ($custom_timezone_offset && $custom_timezone_offset != '') {
update_option('ahcpro_custom_timezone', $custom_timezone_offset);
}
$delete_plugin_data = (isset($_POST['delete_plugin_data'])) ? $_POST['delete_plugin_data'] : 0;
$ahcpro_save_ips = (isset($_POST['ahcpro_save_ips'])) ? $_POST['ahcpro_save_ips'] : 0;
update_option('ahcpro_delete_plugin_data_on_uninstall', $delete_plugin_data);
update_option('ahcpro_save_ips_opn', $ahcpro_save_ips);
$ahcproExcludeRoles = '';
if (isset($_POST['ahcproExcludeRoles'])) {
foreach ($_POST['ahcproExcludeRoles'] as $v) {
$ahcproExcludeRoles .= $v . ",";
}
}
$ahcproUserRoles = '';
if (isset($_POST['ahcproUserRoles'])) {
foreach ($_POST['ahcproUserRoles'] as $v) {
$ahcproUserRoles .= $v . ",";
}
}
update_option('ahcpro_hide_top_bar_icon', $ahcpro_hide_top_bar_icon);
update_option('ahcpro_haships', $ahcpro_haships);
// Data retention period (in days) - 0 means "keep forever"
if (isset($_POST['ahcpro_data_retention_days'])) {
$retention = (int) $_POST['ahcpro_data_retention_days'];
// Only allow whitelisted values
if (!in_array($retention, array(0, 30, 90, 180), true)) {
$retention = 0;
}
update_option('ahcpro_data_retention_days', $retention);
}
$ahcproUserRoles = substr($ahcproUserRoles, 0, -1);
update_option('ahcproUserRoles', $ahcproUserRoles);
$ahcproExcludeRoles = substr($ahcproExcludeRoles, 0, -1);
update_option('ahcproExcludeRoles', $ahcproExcludeRoles);
$post_id = $wpdb->get_results("SELECT `set_id` FROM `ahc_settings` WHERE `site_id` =" . get_current_blog_id());
if (empty($post_id)) {
$sql = $wpdb->prepare("INSERT INTO `ahc_settings` (`set_id`, `set_hits_days`, `set_ajax_check`, `set_ips`, `set_google_map`, `site_id`) VALUES (NULL, %s, %s, %s, %s ,%s); ", $set_hits_days, $set_ajax_check, $set_ips, $set_google_map, get_current_blog_id());
$data_set = $wpdb->query($sql);
} else {
$sql = $wpdb->prepare("UPDATE `ahc_settings` set `set_hits_days` = %s, `set_ajax_check` = %s, `set_ips` = %s, `set_google_map` = %s where `site_id` = %d ", $set_hits_days, $set_ajax_check, $set_ips, $set_google_map, get_current_blog_id());
$data_set = $wpdb->query($sql);
}
if ($data_set !== false) {
return true;
}
return false;
}
function ahcpro_rate_us($plugin_url, $box_color = '#1D1F21')
{
$ret = '
<script language="javascript">
setTimeout(function() {
$(\'#ratingdiv\').hide();
}, 1000);
</script>
<style type="text/css">
.rate_box{
background-color:' . $box_color . ';
color:#ffffff;
}
.rating {
unicode-bidi: bidi-override;
direction: rtl;
}
.link_wp{
color:#EDAE42 !important
}
.rating > span {
display: inline-block;
position: relative;
width: 1.1em;
font-size:40px;
color:yellow;
content: "\2605";
}
.rating > span:hover:before,
.rating > span:hover ~ span:before {
content: "\2605";
position: absolute;
color:yellow;
}
</style>';
$ret .= '<div class="row rate_box" id="ratingdiv">
<div class="col-md-6">
<br />
<p>
<strong>Do you like this plugin?</strong><br /> Please take a few seconds to <a class="link_wp" href="' . $plugin_url . '" target="_blank">rate it on WordPress.org!</a></p>
</div>
<div class="col-md-6">
<div class="rating">';
for ($r = 1; $r <= 5; $r++) {
$ret .= '<span onclick="window.open(\'' . $plugin_url . '\',\'_blank\')">☆</span>';
}
$ret .= '</div>
</div>
</div>';
return $ret;
}
function ahcpro_get_save_settings()
{
global $wpdb;
$table_exist = ahcpro_check_table_exists('ahc_settings');
if ($table_exist) {
if (!ahcpro_check_table_column_exists('ahc_settings', 'site_id')) {
ahcpro_multisite_init();
}
$result = $wpdb->get_results("SELECT set_hits_days, set_ajax_check, set_ips, set_google_map FROM ahc_settings where site_id = " . get_current_blog_id(), OBJECT);
if ($result !== false) {
return $result;
}
}
return false;
}
function ahcpro_get_timezone_string()
{
// First, try the custom timezone option
$custom_timezone = get_option('ahcpro_custom_timezone');
if (!empty($custom_timezone) && in_array($custom_timezone, timezone_identifiers_list())) {
return $custom_timezone;
}
// Fallback to WordPress timezone_string
$wp_timezone = get_option('timezone_string');
if (!empty($wp_timezone) && in_array($wp_timezone, timezone_identifiers_list())) {
return $wp_timezone;
}
// Final fallback
return 'UTC';
}
function ahcpro_get_current_timezone_offset()
{
$timezone_name = ahcpro_get_timezone_string();
try {
$timezone = new DateTimeZone($timezone_name);
$datetime = new DateTime('now', $timezone);
return $datetime->format('P'); // Returns +03:00 format
} catch (Exception $e) {
error_log('Timezone offset error: ' . $e->getMessage());
return '+00:00';
}
}
function ahcpro_GetWPTimezoneString()
{
// if site timezone string exists, return it
if ($timezone = get_option('timezone_string'))
return $timezone;
// get UTC offset, if it isn't set then return UTC
if (0 === ($utc_offset = get_option('gmt_offset', 0)))
return 'UTC';
// adjust UTC offset from hours to seconds
$utc_offset *= 3600;
// attempt to guess the timezone string from the UTC offset
if ($timezone = timezone_name_from_abbr('', $utc_offset, 0)) {
return $timezone;
}
// last try, guess timezone string manually
$is_dst = date('I');
foreach (timezone_abbreviations_list() as $abbr) {
foreach ($abbr as $city) {
if ($city['dst'] == $is_dst && $city['offset'] == $utc_offset)
return $city['timezone_id'];
}
}
// fallback to UTC
return 'UTC';
}
function ahcpro_last_hit_date()
{
global $wpdb;
$custom_timezone_offset = ahcpro_get_current_timezone_offset();
$sql = "SELECT max(CONVERT_TZ(vtr_date,'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "')) as last_date FROM ahc_recent_visitors where site_id =" . get_current_blog_id();
//echo $sql = "SELECT max(vtr_date)) as last_date FROM ahc_recent_visitors";
$result = $wpdb->get_results($sql, OBJECT);
if ($result !== false) {
return $result[0]->last_date;
}
return ahcpro_localtime('Y-m-d', time());
}
function ahcpro_getCountriesCount($site_id = '')
{
if ($site_id == '') {
$site_id = get_current_blog_id();
}
global $wpdb;
$result = $wpdb->get_results("SELECT COUNT( `ctr_id` ) cnt FROM ahc_countries where site_id = " . $site_id, OBJECT);
if ($result !== false) {
return $result[0]->cnt;
}
return false;
}
function ahcpro_getBrowsersCount($site_id = '')
{
if ($site_id == '') {
$site_id = get_current_blog_id();
}
global $wpdb;
$result = $wpdb->get_results("SELECT COUNT( `bsr_id` ) cnt FROM ahc_browsers where site_id = " . $site_id, OBJECT);
if ($result !== false) {
return $result[0]->cnt;
}
return false;
}
function ahcpro_getSearchEnginesCount()
{
global $wpdb;
$result = $wpdb->get_results("SELECT COUNT( `srh_id` ) cnt FROM ahc_search_engines", OBJECT);
if ($result !== false) {
return $result[0]->cnt;
}
return false;
}
function ahcpro_set_default_options()
{
ini_set('upload_max_filesize', '10M');
// if (is_multisite())
// die('<b style="color:red">Sorry, This plugin can\'t be activated networkwide :(</b>');
if (is_plugin_active('visitors-traffic-real-time-statistics/Visitors-Traffic-Real-Time-Statistics.php')) {
deactivate_plugins('visitors-traffic-real-time-statistics/Visitors-Traffic-Real-Time-Statistics.php');
}
// plugin activation
require_once("database_basics_data.php");
if (get_option('ahcpro_wp_hits_counter_options') === false) {
$plugin_options = array();
$plugin_options['ahc_version'] = '1.0';
$plugin_options['available_languages'] = array('ar' => 'عربي', 'en' => 'English');
$plugin_options['ahc_lang'] = 'en';
$plugin_options['user_roles_to_not_track'] = array('administrator' => true, 'editor' => true, 'author' => true, 'contributor' => true, 'subscriber' => false);
add_option('ahcpro_wp_hits_counter_options', $plugin_options);
}
set_time_limit(300);
if (ahcpro_create_database_tables()) {
ahcpro_multisite_init();
if (is_multisite()) {
$get_site_ids = get_sites();
foreach ($get_site_ids as $row) {
if (ahcpro_getCountriesCount($row->blog_id) == 0) {
ahcpro_insert_countries_into_table($internetCountryCodes, $contriesLatLng, $row->blog_id);
}
if (ahcpro_getVisitsTime($row->blog_id) == 0) {
ahcpro_insert_visit_times_into_table($dayHours, $row->blog_id);
}
if (ahcpro_getBrowsersCount($row->blog_id) == 0) {
//echo $row->blog_id;
ahcpro_insert_browsers_into_table($browsers, $row->blog_id);
}
}
} else {
if (ahcpro_getCountriesCount(1) == 0) {
ahcpro_insert_countries_into_table($internetCountryCodes, $contriesLatLng, 1);
}
if (ahcpro_getVisitsTime(1) == 0) {
ahcpro_insert_visit_times_into_table($dayHours, 1);
}
if (ahcpro_getBrowsersCount(1) == 0) {
//echo $row->blog_id;
ahcpro_insert_browsers_into_table($browsers, 1);
}
}
if (ahcpro_getSearchEnginesCount() == 0) {
ahcpro_insert_search_engines_into_table($searchEngines);
}
}
//ahcpro_update_tables();
}
if (is_multisite()) {
add_action('wp_initialize_site', 'ahcpro_action_wp_initialize_site', 900);
function ahcpro_action_wp_initialize_site(WP_Site $new_site)
{
$site_id = $new_site->blog_id;
require_once("database_basics_data.php");
if (ahcpro_getCountriesCount($site_id) == 0) {
ahcpro_insert_countries_into_table($internetCountryCodes, $contriesLatLng, $site_id);
}
if (ahcpro_getVisitsTime($site_id) == 0) {
ahcpro_insert_visit_times_into_table($dayHours, $site_id);
}
if (ahcpro_getBrowsersCount($site_id) == 0) {
ahcpro_insert_browsers_into_table($browsers, $site_id);
}
}
}
//--------------------------------------------
/**
* Called when plugin is deactivated
*
* @return void
*/
function ahcpro_unset_default_options() {
// Clear scheduled cleanup cron
$timestamp = wp_next_scheduled('ahcpro_daily_cleanup');
if ($timestamp) {
wp_unschedule_event($timestamp, 'ahcpro_daily_cleanup');
}
}
//--------------------------------------------
/**
* Data Retention Cleanup
* Deletes statistics records older than the configured retention period
* Affected tables: ahc_hits, ahc_recent_visitors, ahc_online_users, ahc_keywords
* Untouched: ahc_visitors (daily aggregates), ahc_countries, ahc_browsers, ahc_settings, etc.
*
* @param int $days Number of days to keep. 0 = keep forever (no cleanup).
* @param bool $dry_run If true, only counts rows that would be deleted (no actual delete).
* @return array ['hits' => N, 'recent_visitors' => N, 'online_users' => N, 'keywords' => N, 'total' => N]
*/
function ahcpro_cleanup_old_data($days = 90, $dry_run = false)
{
global $wpdb;
$result = array(
'hits' => 0,
'recent_visitors' => 0,
'online_users' => 0,
'keywords' => 0,
'total' => 0,
);
// Safety: 0 or negative means "keep forever"
$days = (int) $days;
if ($days <= 0) {
return $result;
}
// Use plugin timezone offset for accurate cutoff
$cutoff_date = date('Y-m-d', strtotime('-' . $days . ' days'));
$cutoff_datetime = $cutoff_date . ' 00:00:00';
$site_id = get_current_blog_id();
// 1) ahc_hits (per-page-view records, biggest table)
if ($dry_run) {
$count = (int) $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM `ahc_hits` WHERE site_id = %d AND hit_date < %s",
$site_id, $cutoff_date
));
$result['hits'] = $count;
} else {
$deleted = $wpdb->query($wpdb->prepare(
"DELETE FROM `ahc_hits` WHERE site_id = %d AND hit_date < %s",
$site_id, $cutoff_date
));
$result['hits'] = $deleted === false ? 0 : (int) $deleted;
}
// 2) ahc_recent_visitors (per-visitor-session records)
if ($dry_run) {
$count = (int) $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM `ahc_recent_visitors` WHERE site_id = %d AND vtr_date < %s",
$site_id, $cutoff_date
));
$result['recent_visitors'] = $count;
} else {
$deleted = $wpdb->query($wpdb->prepare(
"DELETE FROM `ahc_recent_visitors` WHERE site_id = %d AND vtr_date < %s",
$site_id, $cutoff_date
));
$result['recent_visitors'] = $deleted === false ? 0 : (int) $deleted;
}
// 3) ahc_online_users (real-time online tracking - timestamp column is `date`)
if ($dry_run) {
$count = (int) $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM `ahc_online_users` WHERE site_id = %d AND `date` < %s",
$site_id, $cutoff_datetime
));
$result['online_users'] = $count;
} else {
$deleted = $wpdb->query($wpdb->prepare(
"DELETE FROM `ahc_online_users` WHERE site_id = %d AND `date` < %s",
$site_id, $cutoff_datetime
));
$result['online_users'] = $deleted === false ? 0 : (int) $deleted;
}
// 4) ahc_keywords (search keywords records)
if ($dry_run) {
$count = (int) $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM `ahc_keywords` WHERE site_id = %d AND kwd_date < %s",
$site_id, $cutoff_date
));
$result['keywords'] = $count;
} else {
$deleted = $wpdb->query($wpdb->prepare(
"DELETE FROM `ahc_keywords` WHERE site_id = %d AND kwd_date < %s",
$site_id, $cutoff_date
));
$result['keywords'] = $deleted === false ? 0 : (int) $deleted;
}
$result['total'] = $result['hits'] + $result['recent_visitors'] + $result['online_users'] + $result['keywords'];
return $result;
}
/**
* Schedule the daily cleanup cron
*/
function ahcpro_schedule_daily_cleanup()
{
if (!wp_next_scheduled('ahcpro_daily_cleanup')) {
wp_schedule_event(time() + 3600, 'daily', 'ahcpro_daily_cleanup');
}
}
add_action('init', 'ahcpro_schedule_daily_cleanup');
/**
* Cron handler — runs daily, deletes old data based on user-configured retention
*/
function ahcpro_daily_cleanup_handler()
{
// Default: keep forever (safe default - matches existing behavior)
$days = (int) get_option('ahcpro_data_retention_days', 180);
if ($days <= 0) {
return; // "Forever" → don't delete anything
}
$result = ahcpro_cleanup_old_data($days, false);
update_option('ahcpro_last_cleanup_time', time());
update_option('ahcpro_last_cleanup_result', $result);
if ($result['total'] > 0) {
error_log(sprintf(
'[ahcpro] Daily cleanup: deleted %d rows (hits:%d, visitors:%d, online:%d, keywords:%d)',
$result['total'], $result['hits'], $result['recent_visitors'], $result['online_users'], $result['keywords']
));
}
}
add_action('ahcpro_daily_cleanup', 'ahcpro_daily_cleanup_handler');
/**
* AJAX handler — preview how many rows will be deleted (no actual delete)
*/
function ahcpro_cleanup_preview_ajax()
{
if (!current_user_can('manage_options')) {
wp_send_json_error(array('message' => 'Insufficient permissions'));
}
check_ajax_referer('ahcpro_cleanup_nonce', 'nonce');
$days = isset($_POST['days']) ? (int) $_POST['days'] : 0;
if ($days <= 0) {
wp_send_json_error(array('message' => 'Invalid retention period'));
}
$result = ahcpro_cleanup_old_data($days, true);
wp_send_json_success($result);
}
add_action('wp_ajax_ahcpro_cleanup_preview', 'ahcpro_cleanup_preview_ajax');
/**
* AJAX handler — actually delete the old data
*/
function ahcpro_cleanup_run_ajax()
{
if (!current_user_can('manage_options')) {
wp_send_json_error(array('message' => 'Insufficient permissions'));
}
check_ajax_referer('ahcpro_cleanup_nonce', 'nonce');
$days = isset($_POST['days']) ? (int) $_POST['days'] : 0;
if ($days <= 0) {
wp_send_json_error(array('message' => 'Invalid retention period'));
}
$result = ahcpro_cleanup_old_data($days, false);
update_option('ahcpro_last_cleanup_time', time());
update_option('ahcpro_last_cleanup_result', $result);
wp_send_json_success($result);
}
add_action('wp_ajax_ahcpro_cleanup_run', 'ahcpro_cleanup_run_ajax');
//--------------------------------------------
/**
* Creates plugin page link in the admin menu
*
* @uses add_menu_page()
* @uses plugins_url()
*
* @return void
*/
function ahcpro_create_admin_menu_link()
{
global $current_user;
$ahcUserRoles = str_ireplace('Array', '', get_option('ahcproUserRoles'));
$ahcproUserRole = explode(',', $ahcUserRoles);
$roles_arr = array();
foreach ($ahcproUserRole as $k => $v) {
$roles_arr[] = strtolower($v);
}
$current_use_roles_ = $current_user->roles;
$current_use_roles_ = (isset($current_use_roles_[0])) ? strtolower($current_use_roles_[0]) : strtolower($current_use_roles_[1]);
if (!in_array($current_use_roles_, $roles_arr) && !current_user_can('manage_options')) {
return;
}
add_menu_page('Visitor Traffic Real Time Statistics pro', 'Visitor Traffic Pro', 'read', 'ahc_hits_counter_menu_pro', 'ahcpro_create_plugin_overview_page', plugins_url('/images/vtrts.png', AHCPRO_PLUGIN_MAIN_FILE));
add_submenu_page('ahc_hits_counter_menu_pro', 'Settings', 'Settings', 'read', 'ahc_hits_counter_settings', 'ahcpro_create_plugin_settings_page');
add_submenu_page('ahc_hits_counter_menu_pro', 'Contact Support', 'Help', 'read', 'ahc_hits_counter_help', 'ahcpro_create_plugin_help_page');
add_submenu_page('ahc_hits_counter_menu_pro', 'Scan QR Code', '<span style="color: #FCB214;">Mobile App</span>', 'read', 'ahcpro_app', 'ahcpro_create_plugin_QR_page');
$ahcpro_custom_timezone = get_option('ahcpro_custom_timezone', false);
if (!$ahcpro_custom_timezone) {
update_option('ahcpro_custom_timezone', get_option('timezone_string'));
add_action('admin_notices', 'admin_notice_to_set_timezone');
}
if (isset($_GET['page']) && $_GET['page'] == 'ahc_hits_counter_settings') {
remove_action('admin_notices', 'admin_notice_to_set_timezone');
}
}
//--------------------------------------------
/**
* Format numbers
*
* @return number
*/
function ahc_pro_NumFormat($num)
{
// تنسيق الأرقام مع فاصلة للآلاف (مثال: 125019 → 125,019)
if (!is_numeric($num)) {
return $num;
}
return number_format((float) $num, 0, '.', ',');
}
//------
function ahcpro_countOnlineusers()
{
global $wpdb;
$sql = "SELECT DISTINCT hit_ip_address FROM `ahc_online_users` WHERE `site_id` = '" . get_current_blog_id() . "' and `date` >= DATE_ADD('" . ahcpro_localtime("Y-m-d H:i:s") . "', INTERVAL -2 MINUTE) ";
$result = $wpdb->get_results($sql, OBJECT);
$online_users = "0";
if ($result !== false) {
$online_users = count($result);
}
if (is_admin()) {
echo json_encode($online_users);
die;
} else {
return $online_users;
}
exit;
//return '0';
}
// Add these lines to register your existing function with a new action name
add_action('wp_ajax_ahcpro_countOnlineusers_adminbar', 'ahcpro_countOnlineusers');
add_action('wp_ajax_nopriv_ahcpro_countOnlineusers_adminbar', 'ahcpro_countOnlineusers');
function ahc_init()
{
add_action('wp_ajax_ahcpro_countOnlineusers', 'ahcpro_countOnlineusers');
add_action('wp_ajax_ahcpro_track_visitor', 'ahcpro_track_visitor');
add_action('wp_ajax_nopriv_ahcpro_track_visitor', 'ahcpro_track_visitor');
}
add_action('admin_init', 'ahc_init');
function ahc_enqueue_scripts()
{
global $post, $wp_query;
$post_id = "HOMEPAGE";
$page_title = '';
$post_type = '';
if (is_singular() || is_page()) {
$post_id = $post->ID;
$page_title = get_the_title($post->ID);
$post_type = get_post_type($post->ID);
}
if (is_home()) {
$post_id = "BLOGPAGE";
}
if (is_archive()) {
$post_id = get_the_archive_title();
}
// تفعيل WordPress Heartbeat API على الـ frontend أولاً
wp_enqueue_script('heartbeat');
// front.js يعتمد على jquery و heartbeat (يُحمَّل بعدهما)
wp_register_script('ahc_front_js', plugins_url('/js/front.js', AHCPRO_PLUGIN_MAIN_FILE), array('jquery', 'heartbeat'), '', true);
wp_enqueue_script('ahc_front_js');
wp_localize_script('ahc_front_js', 'ahc_ajax_front', array(
'ajax_url' => admin_url('admin-ajax.php'),
'page_id' => $post_id,
'page_title' => $page_title,
'post_type' => $post_type,
'visitor_ip' => ahcpro_get_client_ip_address(),
));
}
add_action('wp_enqueue_scripts', 'ahc_enqueue_scripts', 1);
//--------------------------------------------
/**
* Creates the main overview page
*
* @return void
*/
function ahcpro_create_plugin_overview_page()
{
require_once(AHCPRO_PLUGIN_ROOT_DIR . AHC_DS . 'lang' . AHC_DS . GlobalsPro::$lang . '_lang.php');
include("overview.php");
}
//--------------------------------------------
/**
* Creates the plugin settings
*
* @return void
*/
function ahcpro_create_plugin_settings_page()
{
require_once(AHCPRO_PLUGIN_ROOT_DIR . AHC_DS . 'lang' . AHC_DS . GlobalsPro::$lang . '_lang.php');
include("ahc_settings.php");
}
//--------------------------------------------
/**
* Creates the plugin help page
*
* @return void
*/
function ahcpro_create_plugin_help_page()
{
require_once(AHCPRO_PLUGIN_ROOT_DIR . AHC_DS . 'lang' . AHC_DS . GlobalsPro::$lang . '_lang.php');
include("ahc_help.php");
}
//--------------------------------------------
/**
* Creates the plugin help page
*
* @return void
*/
function ahcpro_create_plugin_QR_page()
{
require_once(AHCPRO_PLUGIN_ROOT_DIR . AHC_DS . 'lang' . AHC_DS . GlobalsPro::$lang . '_lang.php');
include("app.php");
}
//--------------------------------------------
/**
* Returns links array of available languages
*
* @uses get_option()
* @uses add_query_arg()
*
* @return array
*/
function ahcpro_get_change_lang_links()
{
$plugin_options = get_option('ahcpro_wp_hits_counter_options');
$links = array();
$i = 0;
foreach ($plugin_options['available_languages'] as $key => $value) {
if (GlobalsPro::$lang != $key) {
$links[$i]['name'] = $value;
$links[$i]['href'] = add_query_arg('ahc_lang', $key);
$i++;
}
}
unset($plugin_options);
unset($i);
return $links;
}
//--------------------------------------------
/**
* Decides whether or not should track the current visitor
*
* @uses is_user_logged_in()
* @uses WP_User::$roles
*
* @return boolean
*/
function ahcpro_should_track_visitor()
{
global $current_user;
$allow = true;
if (is_user_logged_in()) {
$user = new WP_User($current_user->ID);
if (!empty($user->roles) && is_array($user->roles)) {
foreach ($user->roles as $role) {
$ahcproExcludeRoles = get_option('ahcproExcludeRoles');
if (isset($ahcproExcludeRoles)) {
$ahcproExcludeRoles = explode(',', $ahcproExcludeRoles);
foreach ($ahcproExcludeRoles as $k => $v) {
if (strtolower($v) == strtolower($role)) {
return false;
}
}
}
/*$found = (isset(GlobalsPro::$plugin_options['user_roles_to_not_track'][$role])) ? GlobalsPro::$plugin_options['user_roles_to_not_track'][$role] : false;
if ($found) {
$allow = false;
break;
}*/
}
}
}
return true;
}
//--------------------------------------------
/**
* Returns true if the current user has administrator role
*
* @uses is_user_logged_in()
* @uses WP_User::$roles
*
* @return boolean
*/
function ahcpro_has_administrator_role()
{
global $user_ID;
$is_admin = false;
if (is_user_logged_in()) {
$user = new WP_User($user_ID);
if (!empty($user->roles) && is_array($user->roles)) {
foreach ($user->roles as $role) {
if ($role == 'administrator') {
$is_admin = true;
break;
}
}
}
}
return $is_admin;
}
//--------------------------------------------
/**
* Check if column exist or not
*
* @uses wpdb::query()
*
* @return boolean
*/
function ahcpro_check_table_column_exists($table_name, $column_name)
{
global $wpdb;
$column = $wpdb->get_row($wpdb->prepare("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s AND COLUMN_NAME = %s ", DB_NAME, $table_name, $column_name));
if (!empty($column)) {
return true;
}
return false;
}
//--------------------------------------------
/**
* Check if Table exist or not
*
* @uses wpdb::query()
*
* @return boolean
*/
function ahcpro_check_table_exists($table_name)
{
global $wpdb;
$table_data = $wpdb->get_row($wpdb->prepare("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s", DB_NAME, $table_name));
if (!empty($table_data)) {
return true;
}
return false;
}
//--------------------------------------------
/**
* Creates database updates plugin tables
*
* @uses wpdb::query()
*
* @return boolean
*/
function ahcpro_update_tables()
{
global $wpdb;
$sqlQueries = array();
// $sqlQueries[] = " drop table IF EXISTS `ahc_settings` ";
// $sqlQueries[] = "
// CREATE TABLE IF NOT EXISTS `ahc_settings` (
// `set_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
// `set_hits_days` int(10) unsigned NOT NULL DEFAULT '14',
// `set_ajax_check` int(10) unsigned NOT NULL DEFAULT '10',
// `set_ips` text DEFAULT NULL,
// `set_google_map` varchar(100) NOT NULL DEFAULT 'today_visitors',
// `site_id` int(10) NOT NULL DEFAULT '1',
// PRIMARY KEY (`set_id`)
// ) DEFAULT CHARSET=utf8";
//$sqlQueries[] = "alter table `ahc_recent_visitors` add COLUMN `ahc_city` varchar(230) NULL";
//$sqlQueries[] = "alter table `ahc_recent_visitors` add COLUMN `ahc_region` varchar(230) NULL";
/* code for error handling : "duplicate column name" : Taslim -Prism */
// foreach ($sqlQueries as $sql) {
// if ($wpdb->query($sql) === false) {
// return false;
// }
// }
return true;
}
function ahcpro_multisite_init()
{
global $wpdb;
$sqlQueries = array();
if (ahcpro_check_table_exists('ahc_browsers') === true && !ahcpro_check_table_column_exists('ahc_browsers', 'site_id')) {
$sqlQueries[] = "ALTER TABLE `ahc_browsers` ADD `site_id` INT(11) NOT NULL DEFAULT '1';";
}
if (ahcpro_check_table_exists('ahc_countries') === true && !ahcpro_check_table_column_exists('ahc_countries', 'site_id')) {
$sqlQueries[] = "ALTER TABLE `ahc_countries` ADD `site_id` INT(11) NOT NULL DEFAULT '1';";
}
if (ahcpro_check_table_exists('ahc_daily_visitors_stats') === true && !ahcpro_check_table_column_exists('ahc_daily_visitors_stats', 'site_id')) {
$sqlQueries[] = "ALTER TABLE `ahc_daily_visitors_stats` ADD `site_id` INT(11) NOT NULL DEFAULT '1';";
}
if (ahcpro_check_table_exists('ahc_hits') === true && !ahcpro_check_table_column_exists('ahc_hits', 'site_id')) {
$sqlQueries[] = "ALTER TABLE `ahc_hits` ADD `site_id` INT(11) NOT NULL DEFAULT '1';";
}
if (ahcpro_check_table_exists('ahc_keywords') === true && !ahcpro_check_table_column_exists('ahc_keywords', 'site_id')) {
$sqlQueries[] = "ALTER TABLE `ahc_keywords` ADD `site_id` INT(11) NOT NULL DEFAULT '1';";
}
if (ahcpro_check_table_exists('ahc_online_users') === true && !ahcpro_check_table_column_exists('ahc_online_users', 'site_id')) {
$sqlQueries[] = "ALTER TABLE `ahc_online_users` ADD `site_id` INT(11) NOT NULL DEFAULT '1';";
}
if (ahcpro_check_table_exists('ahc_recent_visitors') === true && !ahcpro_check_table_column_exists('ahc_recent_visitors', 'site_id')) {
$sqlQueries[] = "ALTER TABLE `ahc_recent_visitors` ADD `site_id` INT(11) NOT NULL DEFAULT '1';";
}
if (ahcpro_check_table_exists('ahc_refering_sites') === true && !ahcpro_check_table_column_exists('ahc_refering_sites', 'site_id')) {
$sqlQueries[] = "ALTER TABLE `ahc_refering_sites` ADD `site_id` INT(11) NOT NULL DEFAULT '1';";
}
if (ahcpro_check_table_exists('ahc_searching_visits') === true && !ahcpro_check_table_column_exists('ahc_searching_visits', 'site_id')) {
$sqlQueries[] = "ALTER TABLE `ahc_searching_visits` ADD `site_id` INT(11) NOT NULL DEFAULT '1';";
}
if (ahcpro_check_table_exists('ahc_search_engine_crawlers') === true && !ahcpro_check_table_column_exists('ahc_search_engine_crawlers', 'site_id')) {
$sqlQueries[] = "ALTER TABLE `ahc_search_engine_crawlers` ADD `site_id` INT(11) NOT NULL DEFAULT '1';";
}
if (ahcpro_check_table_exists('ahc_settings') === true && !ahcpro_check_table_column_exists('ahc_settings', 'site_id')) {
$sqlQueries[] = "ALTER TABLE `ahc_settings` ADD `site_id` INT(11) NOT NULL DEFAULT '1';";
}
if (ahcpro_check_table_exists('ahc_title_traffic') === true && !ahcpro_check_table_column_exists('ahc_title_traffic', 'site_id')) {
$sqlQueries[] = "ALTER TABLE `ahc_title_traffic` ADD `site_id` INT(11) NOT NULL DEFAULT '1';";
}
if (ahcpro_check_table_exists('ahc_visitors') === true && !ahcpro_check_table_column_exists('ahc_visitors', 'site_id')) {
$sqlQueries[] = "ALTER TABLE `ahc_visitors` ADD `site_id` INT(11) NOT NULL DEFAULT '1';";
}
if (ahcpro_check_table_exists('ahc_visits_time') === true && !ahcpro_check_table_column_exists('ahc_visits_time', 'site_id')) {
$sqlQueries[] = "ALTER TABLE `ahc_visits_time` ADD `site_id` INT(11) NOT NULL DEFAULT '1';";
}
if (ahcpro_check_table_exists('ahc_recent_visitors') === true && ahcpro_check_table_column_exists('ahc_recent_visitors', 'ahc_city') === false) {
$sqlQueries[] = "alter table `ahc_recent_visitors` add COLUMN `ahc_city` varchar(230) NULL";
}
if (ahcpro_check_table_exists('ahc_recent_visitors') === true && ahcpro_check_table_column_exists('ahc_recent_visitors', 'ahc_region') === false) {
$sqlQueries[] = "alter table `ahc_recent_visitors` add COLUMN `ahc_region` varchar(230) NULL";
}
if (ahcpro_check_table_exists('ahc_browsers') === true && ahcpro_check_table_column_exists('ahc_browsers', 'bsr_id') === true) {
$sqlQueries[] = "ALTER TABLE `ahc_browsers` CHANGE `bsr_id` `bsr_id` INT(3) UNSIGNED NOT NULL AUTO_INCREMENT";
}
if (count($sqlQueries)) {
foreach ($sqlQueries as $sql) {
$wpdb->query($sql);
}
}
}
function ahcpro_init()
{
global $wpdb;
$sqlQueries = array();
if (ahcpro_check_table_exists('ahc_visitors') === true && ahcpro_check_table_column_exists('ahc_visitors', 'vst_date')) {
$sqlQueries[] = "ALTER TABLE `ahc_visitors` CHANGE `vst_date` `vst_date` DATETIME NOT NULL";
}
if (ahcpro_check_table_exists('ahc_searching_visits') === true && ahcpro_check_table_column_exists('ahc_searching_visits', 'vtsh_date')) {
$sqlQueries[] = "ALTER TABLE `ahc_searching_visits` CHANGE `vtsh_date` `vtsh_date` DATETIME NOT NULL";
}
$sqlQueries[] = "CREATE TABLE IF NOT EXISTS `ahc_online_users`
(
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY(`id`),
`hit_ip_address` VARCHAR(50) NOT NULL,
`hit_page_id` VARCHAR(30) NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) DEFAULT CHARSET=utf8";
if (count($sqlQueries)) {
foreach ($sqlQueries as $sql) {
$wpdb->query($sql);
}
}
}
function ahcpro_add_settings()
{
global $wpdb;
$sql_ahc_settings = "
CREATE TABLE IF NOT EXISTS `ahc_settings` (
`set_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`set_hits_days` int(10) unsigned NOT NULL DEFAULT '14',
`set_ajax_check` int(10) unsigned NOT NULL DEFAULT '10',
`set_ips` text DEFAULT NULL,
`set_google_map` varchar(100) NOT NULL DEFAULT 'today_visitors',
`site_id` INT(11) NOT NULL DEFAULT '1',
PRIMARY KEY (`set_id`)) DEFAULT CHARSET=utf8;
";
$wpdb->query($sql_ahc_settings);
if (!ahcpro_check_table_column_exists('ahc_settings', 'site_id')) {
ahcpro_multisite_init();
}
$sql = "insert into `ahc_settings` (set_id, set_hits_days, set_ajax_check, set_ips, set_google_map,site_id) values (1, 14, 15, null, 'today_visitors'," . get_current_blog_id() . ")";
if ($wpdb->query($sql) === false) {
return false;
}
return true;
}
//--------------------------------------------
/**
* Creates database plugin tables
*
* @uses wpdb::query()
*
* @return boolean
*/
function ahcpro_create_database_tables()
{
global $wpdb;
$sqlQueries = array();
$sqlQueries[] = "CREATE TABLE IF NOT EXISTS `ahc_online_users`
(
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY(`id`),
`hit_ip_address` VARCHAR(50) NOT NULL,
`hit_page_id` VARCHAR(30) NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) DEFAULT CHARSET=utf8";
$sqlQueries[] = "CREATE TABLE IF NOT EXISTS `ahc_hits`
(
`hit_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY(`hit_id`),
`hit_ip_address` VARCHAR(50) NOT NULL,
`hit_user_agent` VARCHAR(200) NOT NULL,
`hit_request_uri` VARCHAR(200) NULL,
`hit_page_id` VARCHAR(30) NOT NULL,
`hit_page_title` VARCHAR(200) NULL,
`ctr_id` INT(3) UNSIGNED NULL,
`hit_referer` VARCHAR(300) NULL,
`hit_referer_site` VARCHAR(100) NULL,
`srh_id` INT(3) UNSIGNED NULL,
`hit_search_words` VARCHAR(200) NULL,
`bsr_id` INT(3) UNSIGNED NOT NULL,
`hit_date` DATE NOT NULL,
`hit_time` TIME NOT NULL
) DEFAULT CHARSET=utf8";
$sqlQueries[] = "
CREATE TABLE IF NOT EXISTS `ahc_settings` (
`set_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`set_id`),
`set_hits_days` int(10) unsigned NOT NULL DEFAULT '14',
`set_ajax_check` int(10) unsigned NOT NULL DEFAULT '10',
`set_ips` text DEFAULT NULL,
`set_google_map` varchar(100) NOT NULL DEFAULT 'today_visitors'
) DEFAULT CHARSET=utf8";
$sqlQueries[] = "CREATE TABLE IF NOT EXISTS `ahc_browsers`
(
`bsr_id` INT(3) UNSIGNED NOT NULL,
PRIMARY KEY(`bsr_id`),
`bsr_name` VARCHAR(100) NOT NULL,
`bsr_icon` VARCHAR(50),
`bsr_visits` INT(11) NOT NULL DEFAULT 0
) DEFAULT CHARSET=utf8";
$sqlQueries[] = "CREATE TABLE IF NOT EXISTS `ahc_search_engines`
(
`srh_id` INT(3) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY(`srh_id`),
`srh_name` VARCHAR(100) NOT NULL,
`srh_query_parameter` VARCHAR(10) NOT NULL,
`srh_icon` VARCHAR(50),
`srh_identifier` VARCHAR(50)
) DEFAULT CHARSET=utf8";
$sqlQueries[] = "CREATE TABLE IF NOT EXISTS `ahc_search_engine_crawlers`
(
`bot_name` VARCHAR(50) NOT NULL,
`srh_id` INT(3) UNSIGNED NOT NULL
) DEFAULT CHARSET=utf8";
$sqlQueries[] = "CREATE TABLE IF NOT EXISTS `ahc_countries`
(
`ctr_id` INT(5) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY(`ctr_id`),
`ctr_name` VARCHAR(100) NOT NULL,
`ctr_internet_code` VARCHAR(5) NOT NULL,
`ctr_latitude` VARCHAR(30) NULL,
`ctr_longitude` VARCHAR(30) NULL,
`ctr_visitors` INT(11) NOT NULL DEFAULT 0,
`ctr_visits` INT(11) NOT NULL DEFAULT 0
) DEFAULT CHARSET=utf8";
$sqlQueries[] = "CREATE TABLE IF NOT EXISTS `ahc_visitors`
(
`vst_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`vst_id`),
`vst_date` DATE NOT NULL,
`vst_visitors` INT(11) UNSIGNED NULL DEFAULT 0,
`vst_visits` INT(11) UNSIGNED NULL DEFAULT 0
) DEFAULT CHARSET=utf8";
$sqlQueries[] = "ALTER TABLE `ahc_visitors` CHANGE `vst_date` `vst_date` DATETIME NOT NULL";
$sqlQueries[] = "CREATE TABLE IF NOT EXISTS `ahc_daily_visitors_stats`
(
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
`vst_date` DATETIME NOT NULL,
`vst_visitors` INT(11) UNSIGNED NULL DEFAULT 0,
`vst_visits` INT(11) UNSIGNED NULL DEFAULT 0
) DEFAULT CHARSET=utf8";
$sqlQueries[] = "CREATE TABLE IF NOT EXISTS `ahc_searching_visits`
(
`vtsh_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`vtsh_id`),
`srh_id` INT(3) UNSIGNED NOT NULL,
`vtsh_date` DATE NOT NULL,
`vtsh_visits` INT(11) UNSIGNED NOT NULL DEFAULT 0
) DEFAULT CHARSET=utf8";
$sqlQueries[] = "ALTER TABLE `ahc_searching_visits` CHANGE `vtsh_date` `vtsh_date` DATETIME NOT NULL";
$sqlQueries[] = "CREATE TABLE IF NOT EXISTS `ahc_refering_sites`
(
`rfr_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`rfr_id`),
`rfr_site_name` VARCHAR(100) NOT NULL,
`rfr_visits` INT(11) UNSIGNED NULL DEFAULT 0
) DEFAULT CHARSET=utf8";
$sqlQueries[] = "CREATE TABLE IF NOT EXISTS `ahc_recent_visitors`
(
`vtr_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`vtr_id`),
`vtr_ip_address` VARCHAR(50) NOT NULL,
`vtr_referer` VARCHAR(300) NULL,
`srh_id` INT(3) UNSIGNED NULL,
`bsr_id` INT(3) UNSIGNED NOT NULL,
`ctr_id` INT(5) UNSIGNED NULL,
`vtr_date` DATE NOT NULL,
`vtr_time` TIME NOT NULL
) DEFAULT CHARSET=utf8";
$sqlQueries[] = "CREATE TABLE IF NOT EXISTS `ahc_keywords`
(
`kwd_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`kwd_id`),
`kwd_ip_address` VARCHAR(50) NOT NULL,
`kwd_keywords` VARCHAR(200) NOT NULL,
`kwd_referer` VARCHAR(300) NOT NULL,
`srh_id` INT(3) UNSIGNED NOT NULL,
`ctr_id` INT(5) UNSIGNED NULL,
`bsr_id` INT(3) UNSIGNED NOT NULL,
`kwd_date` DATE NOT NULL,
`kwd_time` TIME NOT NULL
) DEFAULT CHARSET=utf8";
$sqlQueries[] = "CREATE TABLE IF NOT EXISTS `ahc_title_traffic`
(
`til_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`til_id`),
`til_page_id` VARCHAR(30) NOT NULL,
`til_page_title` VARCHAR(100),
`til_hits` INT(11) UNSIGNED NOT NULL
) DEFAULT CHARSET=utf8";
$sqlQueries[] = "CREATE TABLE IF NOT EXISTS `ahc_visits_time`
(
`vtm_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`vtm_id`),
`vtm_time_from` TIME NOT NULL,
`vtm_time_to` TIME NOT NULL,
`vtm_visitors` INT(11) UNSIGNED NOT NULL DEFAULT 0,
`vtm_visits` INT(11) UNSIGNED NOT NULL DEFAULT 0
) DEFAULT CHARSET=utf8";
/* $sqlQueries[] = "alter table `ahc_recent_visitors` add COLUMN `ahc_city` varchar(230) NULL";
$sqlQueries[] = "alter table `ahc_recent_visitors` add COLUMN `ahc_region` varchar(230) NULL";
*/
foreach ($sqlQueries as $sql) {
if ($wpdb->query($sql) === false) {
//return false;
}
}
return true;
}
//--------------------------------------------
/**
* Inserts countries into ahc_countroes table
*
* @uses wpdb::insert()
*
* @param array $internetCountryCodes. internet codes and names of countries
* @param array $contriesLatLng. LatLng of countries
* @return boolean
*/
function ahcpro_insert_countries_into_table($internetCountryCodes, $contriesLatLng, $site_id = 1)
{
global $wpdb;
$c = 1;
foreach ($internetCountryCodes as $internetCode => $countryName) {
$ctr_latitude = $ctr_longitude = NULL;
if (isset($contriesLatLng[$internetCode])) {
$ctr_latitude = $contriesLatLng[$internetCode][0];
$ctr_longitude = $contriesLatLng[$internetCode][1];
}
$result = $wpdb->insert(
'ahc_countries',
array(
'ctr_name' => $countryName,
'ctr_internet_code' => $internetCode,
'ctr_latitude' => $ctr_latitude,
'ctr_longitude' => $ctr_longitude,
'site_id' => $site_id
),
array(
'%s',
'%s',
'%s',
'%s',
'%d'
)
);
if ($result === false) {
return false;
}
}
return true;
}
//--------------------------------------------
/**
* Inserts search engines into ahc_search_engines table
*
* @uses wpdb::insert()
* @uses wpdb::$insert_id
*
* @param array $searchEngines.
* @return boolean
*/
function ahcpro_insert_search_engines_into_table($searchEngines)
{
global $wpdb;
foreach ($searchEngines as $se) {
$result = $wpdb->insert(
'ahc_search_engines',
array(
'srh_name' => $se['srh_name'],
'srh_query_parameter' => $se['srh_query_parameter'],
'srh_icon' => $se['srh_icon'],
'srh_identifier' => $se['srh_identifier'],
),
array(
'%s',
'%s',
'%s',
'%s',
'%d'
)
);
if ($result !== false) {
$srh_id = $wpdb->insert_id;
if (is_multisite()) {
$get_site_ids = get_sites();
foreach ($get_site_ids as $row) {
foreach ($se['crawlers'] as $crawler) {
$result2 = $wpdb->insert(
'ahc_search_engine_crawlers',
array(
'bot_name' => $crawler,
'srh_id' => $srh_id,
'site_id' => $row->blog_id
),
array(
'%s',
'%d',
'%d'
)
);
if ($result2 === false) {
return false;
}
}
}
} else {
foreach ($se['crawlers'] as $crawler) {
$result2 = $wpdb->insert(
'ahc_search_engine_crawlers',
array(
'bot_name' => $crawler,
'srh_id' => $srh_id,
'site_id' => 1
),
array(
'%s',
'%d',
'%d'
)
);
if ($result2 === false) {
return false;
}
}
}
} else {
return false;
}
}
return true;
}
//--------------------------------------------
/**
* Inserts browsers into ahc_browsers table
*
* @uses wpdb::insert()
*
* @param array $browsers
* @return boolean
*/
function ahcpro_insert_browsers_into_table($browsers, $site_id = 1)
{
global $wpdb;
foreach ($browsers as $browser) {
$result = $wpdb->insert(
'ahc_browsers',
array(
'bsr_id' => '',
'bsr_name' => $browser['bsr_name'],
'bsr_icon' => $browser['bsr_icon'],
'site_id' => $site_id
),
array(
'%d',
'%s',
'%s',
'%d'
)
);
if ($result === false) {
return false;
}
}
return true;
}
//--------------------------------------------
/**
* Inserts periods into ahc_visits_time table
*
* @uses wpdb::insert()
*
* @param array $dayHours
* @return boolean
*/
function ahcpro_insert_visit_times_into_table($dayHours, $site_id = 1)
{
global $wpdb;
foreach ($dayHours as $t) {
$result = $wpdb->insert(
'ahc_visits_time',
array(
'vtm_time_from' => $t['vtm_time_from'],
'vtm_time_to' => $t['vtm_time_to'],
'vtm_visitors' => 0,
'site_id' => $site_id
),
array(
'%s',
'%s',
'%d',
'%d'
)
);
if ($result === false) {
return false;
}
}
return true;
}
//--------------------------------------------
/**
* Returns the first and last days of the week of the date you pass
*
* @param string $date
* @param string $format Optional
* @return array
*/
function ahcpro_get_week_limits($date, $format = 'Y-m-d')
{
$custom_timezone_offset = ahcpro_get_current_timezone_offset();
$beginingDay = new DateTime($date);
$custom_timezone = new DateTimeZone(ahcpro_get_timezone_string());
$endingDay = new DateTime($date);
$date = new DateTime($date);
/*
switch ($date->format('w')) {
case 0: // sun
//$beginingDay->modify('-1 day');
$endingDay->modify('+6 day');
break;
case 1: // mon
$beginingDay->modify('-1 day');
$endingDay->modify('+5 day');
break;
case 2: // Tue
$beginingDay->modify('-2 day');
$endingDay->modify('+4 day');
break;
case 3: // Wed
$beginingDay->modify('-3 day');
$endingDay->modify('+3 day');
break;
case 4: // Thu
$beginingDay->modify('-4 day');
$endingDay->modify('+2 day');
break;
case 6: // Fri
$beginingDay->modify('-5 day');
$endingDay->modify('+1 day');
break;
}*/
$beginingDay->modify('-6 day');
//$endingDay->modify();
$day = ahcpro_localtime('w');
//$beginingDay->modify('-'.$day.' days');
//$endingDay->modify('+'.(6-$day).' days');
return array(0 => $beginingDay->format($format), 1 => $endingDay->format($format));
}
//--------------------------------------------
/**
* Return counts visitors and visits in certain day (today|yesterday), certain period(last week, last month, last year) or total
*
* @uses wpdb::prepare()
* @uses wpdb::get_results()
*
* @param string $period Optional
* @return mixed
*/
function ahcpro_get_visitors_visits_in_period($period = 'total')
{
global $wpdb;
$custom_timezone_offset = ahcpro_get_current_timezone_offset();
$custom_timezone = new DateTimeZone(ahcpro_get_timezone_string());
// echo AHCPRO_SERVER_CURRENT_TIMEZONE;
$current_date = new DateTime();
$current_date->setTimezone($custom_timezone);
$date = new DateTime();
$date->setTimezone($custom_timezone);
$sql = "SELECT SUM(vst_visitors) AS vst_visitors, SUM(vst_visits) AS vst_visits
FROM `ahc_visitors`
WHERE site_id = " . get_current_blog_id();
$results = false;
switch ($period) {
case 'today':
$sql .= " AND DATE(CONVERT_TZ(vst_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) = '" . ahcpro_localtime('Y-m-d') . "'";
//$sql .= " AND DATE(vst_date) = DATE(NOW())";
$results = $wpdb->get_results($sql, OBJECT);
break;
case 'yesterday':
$date->modify('-1 day');
$sql .= " AND DATE(CONVERT_TZ(vst_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) = %s";
$results = $wpdb->get_results($wpdb->prepare($sql, $date->format('Y-m-d')), OBJECT);
break;
case 'week': // last 7 days
$limits = ahcpro_get_week_limits($date->format('Y-m-d'));
$sql .= " AND DATE(CONVERT_TZ(vst_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) >= %s AND DATE(CONVERT_TZ(vst_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) <= %s";
$results = $wpdb->get_results($wpdb->prepare($sql, $limits[0], $limits[1]), OBJECT);
break;
case 'month':
$sql .= " AND DATE(CONVERT_TZ(vst_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) >= %s AND DATE(CONVERT_TZ(vst_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) <= %s";
$results = $wpdb->get_results($wpdb->prepare($sql, $date->modify('-30 day')->format('Y-m-d'), $current_date->format('Y-m-d')), OBJECT);
break;
case 'year':
$sql .= " AND DATE(CONVERT_TZ(vst_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) >= %s AND DATE(CONVERT_TZ(vst_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) <= %s";
//$results = $wpdb->get_results($wpdb->prepare($sql, $date->format('Y-01-01'), $date->format('Y-12-31')), OBJECT);
$results = $wpdb->get_results($wpdb->prepare($sql, $date->modify('-365 day')->format('Y-m-d'), $current_date->format('Y-m-d')), OBJECT);
break;
default:
$results = $wpdb->get_results($sql, OBJECT);
}
//echo $wpdb->last_query.'<br />';
if ($results !== false) {
return array(
'visitors' => (empty($results[0]->vst_visitors) ? 0 : $results[0]->vst_visitors),
'visits' => (empty($results[0]->vst_visits) ? 0 : $results[0]->vst_visits)
);
} else {
return false;
}
}
//--------------------------------------------
/**
* Return visitors visits that came from search engine in a period from today
*
* @uses wpdb::prepare()
* @uses wpdb::get_results()
*
* @return array
*/
function ahcpro_get_serch_visits_by_date()
{
global $wpdb;
$response = array();
$sql = "SELECT ase.srh_name, asv.vtsh_date, asv.srh_id, SUM(asv.vtsh_visits) as vtsh_visits FROM `ahc_searching_visits` asv, `ahc_search_engines` ase where asv.site_id = " . get_current_blog_id() . " and asv.srh_id = ase.srh_id GROUP by asv.srh_id order by SUM(asv.vtsh_visits) DESC";
$results = $wpdb->get_results($sql, OBJECT);
if ($results !== false) {
$response['success'] = true;
$response['data']['dates'] = array();
foreach ($results as $r) {
$response['data']['search_engines'][$r->srh_name][] = $r->vtsh_visits;
}
} else {
$response['success'] = false;
}
return $response;
}
//--------------------------------------------
/**
* Returns the total visits by search engines
*
* @uses wpdb::get_results()
*
* @return mixed
*/
function ahcpro_get_total_visits_by_search_engines()
{
global $wpdb;
$result = $wpdb->get_results("SELECT SUM(vtsh_visits) AS total FROM ahc_searching_visits where site_id = " . get_current_blog_id(), OBJECT);
if ($result !== false) {
return $result[0]->total;
}
return false;
}
//--------------------------------------------
/**
* Return counts visits happened by search engine result in certain day (today|yesterday), certain period(last week, last month, last year) or total
*
* @uses wpdb::prepare()
* @uses wpdb::get_results()
*
* @param string $period Optional
* @return mixed
*/
function ahcpro_get_hits_search_engines_referers($period = 'total')
{
global $wpdb;
$custom_timezone_offset = ahcpro_get_current_timezone_offset();
$custom_timezone = new DateTimeZone(ahcpro_get_timezone_string());
$date = new DateTime();
$date->setTimezone($custom_timezone);
$base_sql = "SELECT ase.srh_name, asv.srh_id, SUM(asv.vtsh_visits) AS vtsh_visits
FROM ahc_searching_visits asv
LEFT JOIN ahc_search_engines ase ON ase.srh_id = asv.srh_id
WHERE asv.site_id = " . get_current_blog_id();
$results = false;
switch ($period) {
case 'today':
$sql = $base_sql . " AND DATE(CONVERT_TZ(vtsh_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) = '" . ahcpro_localtime('Y-m-d') . "' GROUP BY asv.srh_id ORDER BY SUM(asv.vtsh_visits) DESC";
$results = $wpdb->get_results($sql, OBJECT);
break;
case 'yesterday':
$date->modify('-1 day');
$sql = $base_sql . " AND DATE(CONVERT_TZ(vtsh_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) = %s GROUP BY asv.srh_id ORDER BY SUM(asv.vtsh_visits) DESC";
$results = $wpdb->get_results($wpdb->prepare($sql, $date->format('Y-m-d')), OBJECT);
break;
case 'week':
$limits = ahcpro_get_week_limits($date->format('Y-m-d'));
$sql = $base_sql . " AND DATE(CONVERT_TZ(vtsh_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) >= %s AND DATE(CONVERT_TZ(vtsh_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) <= %s GROUP BY asv.srh_id ORDER BY SUM(asv.vtsh_visits) DESC";
$results = $wpdb->get_results($wpdb->prepare($sql, $limits[0], $limits[1]), OBJECT);
break;
case 'month':
$sql = $base_sql . " AND DATE(CONVERT_TZ(vtsh_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) >= %s AND DATE(CONVERT_TZ(vtsh_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) <= %s GROUP BY asv.srh_id ORDER BY SUM(asv.vtsh_visits) DESC";
$results = $wpdb->get_results($wpdb->prepare($sql, $date->format('Y-m-01'), $date->format('Y-m-t')), OBJECT);
break;
case 'year':
$sql = $base_sql . " AND DATE(CONVERT_TZ(vtsh_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) >= %s AND DATE(CONVERT_TZ(vtsh_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) <= %s GROUP BY asv.srh_id ORDER BY SUM(asv.vtsh_visits) DESC";
$results = $wpdb->get_results($wpdb->prepare($sql, $date->format('Y-01-01'), $date->format('Y-12-31')), OBJECT);
break;
case 'alltime':
case 'total':
$sql = $base_sql . " GROUP BY asv.srh_id ORDER BY SUM(asv.vtsh_visits) DESC";
$results = $wpdb->get_results($sql, OBJECT);
break;
default:
// Return empty array for invalid periods
return array();
}
$hitsReferers = array();
if ($results !== false && !empty($results)) {
foreach ($results as $r) {
$hitsReferers[$r->srh_name] = $r->vtsh_visits;
}
return $hitsReferers;
}
return array();
}
//--------------------------------------------
/**
* Retrieves all search engines
*
* @uses wpdb::get_results()
*
* @return mixed
*/
function ahcpro_get_all_search_engines()
{
global $wpdb;
$sql = "SELECT `srh_id`, `srh_name`, `srh_icon` FROM `ahc_search_engines`";
$searchEngines = array();
$c = 0;
$results = $wpdb->get_results($sql, OBJECT);
if ($results !== false) {
foreach ($results as $re) {
$searchEngines[$c]['srh_id'] = $re->srh_id;
$searchEngines[$c]['srh_name'] = $re->srh_name;
$searchEngines[$c]['srh_icon'] = $re->srh_icon;
$c++;
}
return $searchEngines;
}
return false;
}
//--------------------------------------------
/**
* Retrieves count of visits order by browsers
*
* @uses wpdb::get_results()
*
* @return array
*/
function ahcpro_get_browsers_hits_counts()
{
global $wpdb;
$sql = "SELECT `bsr_id`, `bsr_name`, `bsr_visits`
FROM `ahc_browsers`
WHERE site_id = " . get_current_blog_id() . " and `bsr_visits` > 0";
$results = $wpdb->get_results($sql, OBJECT);
$response = array();
if ($results !== false) {
$response['success'] = true;
$response['data'] = array();
$c = 0;
foreach ($results as $bsr) {
$response['data'][$c]['bsr_id'] = $bsr->bsr_id;
$response['data'][$c]['bsr_name'] = $bsr->bsr_name;
$response['data'][$c]['hits'] = $bsr->bsr_visits;
$c++;
}
} else {
$response['success'] = false;
}
return $response;
}
//--------------------------------------------
/**
* Retrieves top referring sites
*
* @uses wpdb::prepare()
* @uses wpdb::get_results()
*
* @return mixed
*/
function ahcpro_get_top_refering_sites($start = '0', $limit = '500')
{
global $wpdb;
$limitCond = "";
if ($start != '' && $limit != '') {
$limitCond = " limit " . intval($start) . "," . intval($limit);
}
$sql = "SELECT rfr_site_name, rfr_visits
FROM `ahc_refering_sites`
where site_id = " . get_current_blog_id() . "
ORDER BY rfr_visits DESC $limitCond";
$results = $wpdb->get_results($sql, OBJECT);
if ($results !== false) {
$arr = array();
$c = 0;
foreach ($results as $referer) {
$arr[$c]['site_name'] = $referer->rfr_site_name;
$arr[$c]['total_hits'] = $referer->rfr_visits;
$c++;
}
return $arr;
} else {
return false;
}
}
//--------------------------------------------
/**
* Retrieves countries related to visits
*
* @uses wpdb::prepare()
* @uses wpdb::get_results()
*
* @return mixed
*/
function ahcpro_get_top_countries($limit = 0, $start = '', $pagelimit = '', $all = '', $cnt = true)
{
global $wpdb;
if ($limit == 0) {
$limit = AHCPRO_TOP_COUNTRIES_LIMIT;
}
if ($cnt == true) {
$sql = "SELECT count(*) FROM `ahc_countries` WHERE site_id = " . get_current_blog_id() . " and ctr_visits > 0 ORDER BY ctr_visitors DESC";
$count = $wpdb->get_var($sql);
return $count;
}
$limitCond = "";
if ($start != '' && $pagelimit != '') {
$limitCond = " limit " . intval($start) . "," . intval($pagelimit);
}
if ($limit > 0 && $pagelimit == "") {
$sql = "SELECT ctr_name, ctr_internet_code, ctr_visitors, ctr_visits
FROM `ahc_countries` WHERE site_id = " . get_current_blog_id() . " and ctr_visits > 0
ORDER BY ctr_visitors DESC
LIMIT %d OFFSET 0";
$results = $wpdb->get_results($wpdb->prepare($sql, $limit), OBJECT);
} else {
$sql = "SELECT ctr_name, ctr_internet_code, ctr_visitors, ctr_visits
FROM `ahc_countries` WHERE site_id = " . get_current_blog_id() . " and ctr_visits > 0
ORDER BY ctr_visitors DESC $limitCond";
$results = $wpdb->get_results($sql, OBJECT);
}
$response = array();
if ($results !== false) {
$new = array();
$response['success'] = true;
$response['data'] = array();
$c = 0;
if ($start == "")
$start = 0;
$rank = $start + 1;
foreach ($results as $ctr) {
$response['data'][$c]['rank'] = $rank;
$furl = plugins_url('/images/flags/' . strtolower($ctr->ctr_internet_code) . '.png', AHCPRO_PLUGIN_MAIN_FILE);
$flag = '<img src="' . $furl . '" border="0" alt="' . $ctr->ctr_name . '" width="30" height="20" onerror="imgFlagError(this)" />';
$response['data'][$c]['flag'] = $flag;
$response['data'][$c]['ctr_name'] = $ctr->ctr_name;
//$response['data'][$c]['ctr_internet_code'] = $ctr->ctr_internet_code;
$response['data'][$c]['visitors'] = $ctr->ctr_visitors;
$response['data'][$c]['visits'] = $ctr->ctr_visits;
if ($all == 1) {
$new[$c]['rank'] = $rank;
$new[$c]['ctr_name'] = $ctr->ctr_name;
$new[$c]['visitors'] = $ctr->ctr_visitors;
$new[$c]['visits'] = $ctr->ctr_visits;
}
$c++;
$rank++;
}
} else {
$response['success'] = false;
}
if ($all == 1) {
return $new;
}
return $response;
}
//--------------------------------------------
/**
* Retrieves countries related to visits
*
* @uses wpdb::prepare()
* @uses wpdb::get_results()
*
* @return mixed
*/
function ahcpro_get_vsitors_by_country($all, $cnt = true, $start = '', $limit = '', $fdt = '', $tdt = '')
{
global $wpdb;
$custom_timezone_offset = ahcpro_get_current_timezone_offset();
$vtr_date = "CONVERT_TZ(concat(vtr_date,' ',vtr_time), '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')";
$cond = "";
if (isset($_POST['t_from_dt']) && $_POST['t_from_dt'] != '' && isset($_POST['t_to_dt']) && $_POST['t_to_dt'] != '' && isset($_POST['section']) && $_POST['section'] == "traffic_index_country") {
$fdt = $_POST['t_from_dt'];
$tdt = $_POST['t_to_dt'];
} else if (isset($_POST['t_from_dt']) && $_POST['t_from_dt'] != '' && isset($_POST['section']) && $_POST['section'] == "traffic_index_country") {
$fdt = $_POST['t_from_dt'];
$fromdt = getFormattedDate($_POST['t_from_dt'], 'yymmdd');
$cond = " and vtr_date ='$fromdt'";
}
if ($fdt != '' && $tdt != '') {
$fromdt = getFormattedDate($fdt, 'yymmdd');
$todt = getFormattedDate($tdt, 'yymmdd');
$cond = "and (DATE($vtr_date) between '" . $fromdt . "' and '$todt')";
//$cond =" and (vtr_date between '$fromdt' and '$todt')";
} else if ($fdt != '') {
$fromdt = getFormattedDate($fdt, 'yymmdd');
$cond = "and DATE($vtr_date) = '" . $fromdt . "'";
//$cond =" and vtr_date ='$fromdt'";
} else {
$cond = "and DATE(CONVERT_TZ(concat(vtr_date,' ',vtr_time),'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "')) = '" . ahcpro_localtime('Y-m-d') . "'";
}
if ($cnt == true) {
/*$sql = "select tot.ctr_name, tot.ctr_internet_code, tot.total from (SELECT c.ctr_name, c.ctr_internet_code, count(1) as total FROM ahc_recent_visitors v, ahc_countries c where v.ctr_id = c.ctr_id $cond group by ctr_name) as tot order by tot.total desc";
$results = $wpdb->get_results($sql, OBJECT);*/
$sql = "select count(*) as cnt from (SELECT c.ctr_name, c.ctr_internet_code, count(1) as total FROM ahc_recent_visitors v, ahc_countries c where v.site_id = " . get_current_blog_id() . " and v.ctr_id = c.ctr_id $cond group by ctr_name ) as tot order by tot.total desc";
return $wpdb->get_var($sql);
}
$limitCond = "";
if ($start != '' && $limit != '') {
$limitCond = " limit $start,$limit";
}
if ($all == 1) {
$limitCond = "";
}
$sql = "select tot.ctr_name, tot.ctr_internet_code, tot.total from (SELECT c.ctr_name, c.ctr_internet_code, count(1) as total FROM ahc_recent_visitors v, ahc_countries c where v.site_id = " . get_current_blog_id() . " and v.ctr_id = c.ctr_id $cond group by ctr_name ) as tot order by tot.total desc $limitCond";
$results = $wpdb->get_results($sql, OBJECT);
//echo $sql;
if ($results !== false) {
$arr = array();
$new = array();
$c = 0;
if ($start == "")
$start = 0;
$no = $start + 1;
$sum = 0;
foreach ($results as $ctr) {
/*if ($ctr->total > 1) {*/
$imgurl = plugins_url('/images/flags/' . strtolower($ctr->ctr_internet_code) . '.png', AHCPRO_PLUGIN_MAIN_FILE);
$arr[$c]['no'] = $no;
$arr[$c]['country'] = '<img src="' . $imgurl . '" border="0" alt="' . $ctr->ctr_name . '" width="30" height="20" onerror="imgFlagError(this)" />';
$arr[$c]['ctr_name'] = $ctr->ctr_name;
$arr[$c]['ctr_internet_code'] = $ctr->ctr_internet_code;
$arr[$c]['total'] = $ctr->total;
if ($all == 1) {
$new[$c]['no'] = $no;
$new[$c]['ctr_name'] = $ctr->ctr_name;
$new[$c]['total'] = $ctr->total;
}
$c++;
$no++;
/*} else {
$sum += 1;
}*/
}
if ($sum > 0) {
$k = count($arr);
$arr[$k]['no'] = $no;
$imgurl = plugins_url('/images/flags/xx.png', AHCPRO_PLUGIN_MAIN_FILE);
$arr[$k]['country'] = '<img src="' . $imgurl . '" border="0" alt="' . $ctr->ctr_name . '" width="30" height="20" onerror="imgFlagError(this)" />';
$arr[$k]['ctr_name'] = 'others';
$arr[$k]['ctr_internet_code'] = 'XX';
$arr[$k]['total'] = $sum;
if ($all == 1) {
$new[$k]['no'] = $no;
$new[$k]['ctr_name'] = 'others';
$new[$k]['total'] = $sum;
}
}
if ($all == 1) {
return $new;
}
return $arr;
} else {
return false;
}
}
//--------------------------------------------
/**
* Retrieves recent visitors
*
* @uses wpdb::prepare()
* @uses wpdb::get_results()
*
* @return mixed
*/
// function ahcpro_get_recent_visitors($all, $cnt = true, $start = '', $limit = '', $year = '', $month = '', $ip = '')
// {
// global $wpdb, $_SERVER;
// $cond = "";
// $cond1 = "";
// $having = '';
// // Get the selected month and year from the form
// $selectedMonth = $month;
// $selectedYear = $year;
// // Calculate the start date
// $r_from_dt = $selectedMonth . '-01-' . $selectedYear;
// // Calculate the end date
// if ($month == date('m', time()) && $year == date('Y', time())) {
// $r_to_dt = date('m-d-Y');
// } else {
// $r_to_dt = date('m-t-Y', strtotime($r_from_dt));
// }
// $ahcpro_save_ips = get_option('ahcpro_save_ips_opn');
// if (isset($_POST['ip_addr']) && $_POST['ip_addr'] != '' && isset($_POST['section']) && $_POST['section'] == 'recent_visitor_by_ip') {
// $ip = trim($_POST['ip_addr']);
// }
// if ($ip != '') {
// $cond .= " and vtr_ip_address like '" . $ip . "%'";
// $cond1 .= " and vtr_ip_address like '" . $ip . "%'";
// }
// if ($r_from_dt != '' && $r_to_dt != '') {
// $fromdt = getFormattedDate($r_from_dt, 'yymmdd');
// $r_to_dt = getFormattedDate($r_to_dt, 'yymmdd');
// $cond .= " having (dt between '$fromdt' and '$r_to_dt')";
// $cond1 .= " and (vtr_date between '$fromdt' and '$r_to_dt')";
// }
// $custom_timezone_offset = ahcpro_get_current_timezone_offset();
// if ($cnt == true) {
// $sql_query = "SELECT count(*) as cnt from (Select DATE_FORMAT(CONVERT_TZ(CONCAT_WS(' ',v.vtr_date,v.vtr_time),'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "'), '%Y-%m-%d') as dt FROM `ahc_recent_visitors` AS v LEFT JOIN `ahc_countries` AS c ON v.ctr_id = c.ctr_id LEFT JOIN `ahc_browsers` AS b ON v.bsr_id = b.bsr_id WHERE v.site_id = " . get_current_blog_id() . " and v.vtr_ip_address NOT LIKE 'UNKNOWN%%' $cond ORDER BY v.vtr_id DESC) as res";
// $count = $wpdb->get_row($sql_query);
// return $count->cnt;
// }
// $limitCond = "";
// if ($start != '' && $limit != '') {
// $limitCond = " LIMIT $start, $limit";
// }
// if ($all == 1) {
// $limitCond = "";
// }
// $sql_query = "SELECT v.vtr_id, (
// SELECT Count(1)
// FROM `ahc_hits`
// WHERE `hit_ip_address` = v.vtr_ip_address
// AND date(`hit_date`) = date(v.vtr_date)
// AND `hit_page_title` !='' ) AS day_hits2, v.vtr_ip_address, v.vtr_referer, DATE_FORMAT(CONVERT_TZ(CONCAT_WS(' ',v.vtr_date,v.vtr_time),'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "'), '%Y-%m-%d') as dt ,DATE_FORMAT(CONVERT_TZ(CONCAT_WS(' ',v.vtr_date,v.vtr_time),'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "'), '%Y-%m-%d') as vtr_date, DATE_FORMAT(CONVERT_TZ(CONCAT_WS(' ',v.vtr_date,v.vtr_time),'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "'), '%H:%i:%s') as vtr_time, v.ahc_city, v.ahc_region,
// c.ctr_name, c.ctr_internet_code, b.bsr_name, b.bsr_icon
// FROM `ahc_recent_visitors` AS v
// LEFT JOIN `ahc_countries` AS c ON v.ctr_id = c.ctr_id
// LEFT JOIN `ahc_browsers` AS b ON v.bsr_id = b.bsr_id
// WHERE v.site_id = " . get_current_blog_id() . " and v.vtr_ip_address NOT LIKE 'UNKNOWN%%' $cond
// ORDER BY v.vtr_id DESC $limitCond";
// // echo $sql_query;
// $results = $wpdb->get_results($sql_query);
// if ($results !== false) {
// $arr = array();
// $new = array();
// $c = 0;
// if (is_array($results)) {
// foreach ($results as $hit) {
// $hit->vtr_ip_address = ahcpro_get_simple_ip($hit->vtr_ip_address);
// $visitDate = new DateTime($hit->vtr_date . ' ' . $hit->vtr_time);
// $arr[$c]['hit_id'] = $hit->vtr_id;
// $hit_referer = (parse_url($hit->vtr_referer, PHP_URL_HOST) == $_SERVER['SERVER_NAME']) ? '' : rawurldecode($hit->vtr_referer);
// $hitip = (!empty($hit_referer) ? '<a href="' . $hit_referer . '" target="_blank"><img src="' . plugins_url('/images/openW.jpg', AHCPRO_PLUGIN_MAIN_FILE) . '" title="Referring url"></a>' : '');
// $arr[$c]['hit_ip_address'] = (get_option('ahcpro_haships') != '1') ? $hit->vtr_ip_address . " " . $hitip : ahcfpro_haship($hit->vtr_ip_address) . " " . $hitip;
// $img = "";
// if ($hit->ctr_internet_code != '') {
// $imgurl = plugins_url('/images/flags/' . strtolower($hit->ctr_internet_code) . '.png', AHCPRO_PLUGIN_MAIN_FILE);
// $img = "<img src='" . $imgurl . "' border='0' width='22' height='18' title='" . $hit->ctr_name . "' onerror='imgFlagError(this)' /> ";
// }
// $bimgurl = plugins_url('/images/browsers/' . $hit->bsr_icon, AHCPRO_PLUGIN_MAIN_FILE);
// // $bimg = '<img src="'.$bimgurl.'" border="0" width="20" height="20" title="'.$hit->bsr_name.'" /> ';
// $arr[$c]['hit_date'] = $hit->vtr_date;
// $arr[$c]['hit_time'] = $hit->vtr_time;
// $arr[$c]['ctr_internet_code'] = $hit->ctr_internet_code;
// $arr[$c]['bsr_name'] = $bimgurl . $hit->bsr_name;
// $arr[$c]['bsr_icon'] = $hit->bsr_icon;
// $arr[$c]['day_hits'] = (1) ? '<button style=" background-color: #4CAF50; /* Green */
// border: none;
// color: white;
// padding: 2px 8px;
// text-align: center;
// text-decoration: none;
// display: inline-block;
// font-size: 16px;" data-hitdate="' . $hit->vtr_date . '" data-hitipaddress="' . $hit->vtr_ip_address . '" data-hitcountry="' . $hit->ctr_name . '-' . $hit->ahc_city . '" data-toggle="modal" data-target="#DayHitsModal">' . $hit->day_hits2 . '</button>' : '/';
// if (strpos($hit->ahc_region, '}')) {
// $arr[$c]['ahc_region'] = "-";
// } else {
// $arr[$c]['ahc_region'] = $hit->ahc_region;
// }
// if (strpos($hit->ahc_city, 'charset')) {
// $arr[$c]['ahc_city'] = '-';
// } else {
// $arr[$c]['ahc_city'] = $hit->ahc_city;
// }
// $arr[$c]['ctr_name'] = $img . $hit->ctr_name . ", " . $hit->ahc_city . ", " . $hit->ahc_region;
// $arr[$c]['time'] = $visitDate->format('d M Y @ h:i a');
// // Calculate session duration for this IP and date
// $session_duration_seconds = $wpdb->get_var($wpdb->prepare(
// "SELECT TIMESTAMPDIFF(SECOND, MIN(CONCAT(hit_date, ' ', hit_time)), MAX(CONCAT(hit_date, ' ', hit_time)))
// FROM ahc_hits
// WHERE hit_ip_address = %s AND hit_date = %s AND site_id = %d",
// $hit->vtr_ip_address,
// $hit->vtr_date,
// get_current_blog_id()
// ));
// if ($session_duration_seconds && $session_duration_seconds > 0) {
// $hours = floor($session_duration_seconds / 3600);
// $minutes = floor(($session_duration_seconds % 3600) / 60);
// $seconds = $session_duration_seconds % 60;
// $duration_str = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds);
// } else {
// $duration_str = '00:00:01';
// }
// $arr[$c]['duration'] = $duration_str;
// if ($all == 1) {
// $new[$c]['hit_ip_address'] = $hit->vtr_ip_address;
// $new[$c]['ctr_name'] = $hit->ctr_name . ", " . $hit->ahc_city . ", " . $hit->ahc_region;
// $new[$c]['time'] = $visitDate->format('d M Y @ h:i a');
// $new[$c]['day_hits'] = ($hit->day_hits2 > 0) ? $hit->day_hits2 : '1';
// }
// $c++;
// }
// }
// if ($all == 1)
// return $new;
// return $arr;
// } else {
// return false;
// }
// }
add_action("wp_ajax_recent_visitor_by_ip", "recent_visitor_by_ip_callback");
function recent_visitor_by_ip_callback()
{
$all = (isset($_REQUEST['page']) && $_REQUEST['page'] == 'all') ? 1 : 0;
// Get search parameters - always get them, let the function decide what to do
$search_year = isset($_REQUEST['year']) ? sanitize_text_field($_REQUEST['year']) : '';
$search_month = isset($_REQUEST['month']) ? sanitize_text_field($_REQUEST['month']) : '';
$search_ip = isset($_REQUEST['ip']) ? sanitize_text_field($_REQUEST['ip']) : '';
// Also check POST data for form submissions (with unique names)
if (isset($_POST['ip_addr']) && !empty($_POST['ip_addr'])) {
$search_ip = sanitize_text_field($_POST['ip_addr']);
}
if (isset($_POST['year']) && !empty($_POST['year'])) {
$search_year = sanitize_text_field($_POST['year']);
}
if (isset($_POST['month']) && !empty($_POST['month'])) {
$search_month = sanitize_text_field($_POST['month']);
}
// Debug logging (remove in production)
error_log('Recent Visitor Search - Year: ' . $search_year . ', Month: ' . $search_month . ', IP: ' . $search_ip);
// Get pagination parameters
$start = isset($_REQUEST['start']) ? intval($_REQUEST['start']) : 0;
$length = isset($_REQUEST['length']) ? intval($_REQUEST['length']) : 10;
// Get count and data
$cnt = ahcpro_get_recent_visitors_modified($all, true, "", "", $search_year, $search_month, $search_ip);
$recentVisitors = ahcpro_get_recent_visitors_modified($all, false, $start, $length, $search_year, $search_month, $search_ip);
$arr = array();
$arr["draw"] = isset($_REQUEST['draw']) ? intval($_REQUEST['draw']) : 0;
$arr["recordsTotal"] = $cnt;
$arr["recordsFiltered"] = $cnt;
$arr['data'] = $recentVisitors ? $recentVisitors : array();
// Set proper headers
header('Content-Type: application/json');
echo json_encode($arr);
wp_die(); // Use wp_die() instead of exit for WordPress AJAX
}
// Modified function to handle search parameters directly
function ahcpro_get_recent_visitors_modified($all, $cnt = true, $start = '', $limit = '', $search_year = '', $search_month = '', $ip = '')
{
global $wpdb;
$cond = "";
$cond1 = "";
// Determine date range based on search parameters
if (
!empty($search_year) && !empty($search_month) &&
($search_year != date('Y') || $search_month != date('m'))
) {
// Use the selected year/month for search
$start_date = $search_year . '-' . str_pad($search_month, 2, '0', STR_PAD_LEFT) . '-01';
$end_date = date('Y-m-t', strtotime($start_date)); // Last day of the month
} else {
// Default: use last 30 days
$end_date = date('Y-m-d'); // Today
$start_date = date('Y-m-d', strtotime('-30 days')); // 30 days ago
}
// Convert to the format expected by the database
$formatted_start = date('m-d-Y', strtotime($start_date));
$formatted_end = date('m-d-Y', strtotime($end_date));
// Handle IP filtering
if (!empty($ip)) {
$ip = sanitize_text_field($ip);
$cond .= $wpdb->prepare(" and vtr_ip_address like %s", $ip . '%');
$cond1 .= $wpdb->prepare(" and vtr_ip_address like %s", $ip . '%');
}
// Use the date range for filtering
if ($formatted_start != '' && $formatted_end != '') {
$fromdt = getFormattedDate($formatted_start, 'yymmdd');
$todt = getFormattedDate($formatted_end, 'yymmdd');
$cond .= $wpdb->prepare(" having (dt between %s and %s)", $fromdt, $todt);
$cond1 .= $wpdb->prepare(" and (vtr_date between %s and %s)", $fromdt, $todt);
}
$custom_timezone_offset = ahcpro_get_current_timezone_offset();
$site_id = get_current_blog_id();
if ($cnt == true) {
$sql_query = $wpdb->prepare(
"SELECT count(*) as cnt from (
SELECT DATE_FORMAT(CONVERT_TZ(CONCAT_WS(' ',v.vtr_date,v.vtr_time),%s,%s), '%%Y-%%m-%%d') as dt
FROM `ahc_recent_visitors` AS v
LEFT JOIN `ahc_countries` AS c ON v.ctr_id = c.ctr_id
LEFT JOIN `ahc_browsers` AS b ON v.bsr_id = b.bsr_id
WHERE v.site_id = %d and v.vtr_ip_address NOT LIKE 'UNKNOWN%%'
AND EXISTS (
SELECT 1 FROM `ahc_hits` h
WHERE h.hit_ip_address = v.vtr_ip_address
AND DATE(h.hit_date) = DATE(v.vtr_date)
AND h.hit_page_title != ''
AND h.site_id = v.site_id
)
$cond
ORDER BY v.vtr_id DESC
) as res",
AHCPRO_SERVER_CURRENT_TIMEZONE,
$custom_timezone_offset,
$site_id
);
$count = $wpdb->get_row($sql_query);
return $count ? $count->cnt : 0;
}
$limitCond = "";
if ($start !== '' && $limit !== '') {
$limitCond = $wpdb->prepare(" LIMIT %d, %d", intval($start), intval($limit));
}
if ($all == 1) {
$limitCond = "";
}
$sql_query = $wpdb->prepare(
"SELECT v.vtr_id,
(SELECT Count(1)
FROM `ahc_hits`
WHERE `hit_ip_address` = v.vtr_ip_address
AND date(`hit_date`) = date(v.vtr_date)
AND `hit_page_title` !=''
AND `site_id` = %d) AS day_hits2,
v.vtr_ip_address,
v.vtr_referer,
DATE_FORMAT(CONVERT_TZ(CONCAT_WS(' ',v.vtr_date,v.vtr_time),%s,%s), '%%Y-%%m-%%d') as dt,
DATE_FORMAT(CONVERT_TZ(CONCAT_WS(' ',v.vtr_date,v.vtr_time),%s,%s), '%%Y-%%m-%%d') as vtr_date,
DATE_FORMAT(CONVERT_TZ(CONCAT_WS(' ',v.vtr_date,v.vtr_time),%s,%s), '%%H:%%i:%%s') as vtr_time,
v.ahc_city,
v.ahc_region,
c.ctr_name,
c.ctr_internet_code,
b.bsr_name,
b.bsr_icon
FROM `ahc_recent_visitors` AS v
LEFT JOIN `ahc_countries` AS c ON v.ctr_id = c.ctr_id
LEFT JOIN `ahc_browsers` AS b ON v.bsr_id = b.bsr_id
WHERE v.site_id = %d and v.vtr_ip_address NOT LIKE 'UNKNOWN%%'
AND EXISTS (
SELECT 1 FROM `ahc_hits` h
WHERE h.hit_ip_address = v.vtr_ip_address
AND DATE(h.hit_date) = DATE(v.vtr_date)
AND h.hit_page_title != ''
AND h.site_id = v.site_id
)
$cond
ORDER BY v.vtr_id DESC $limitCond",
$site_id,
AHCPRO_SERVER_CURRENT_TIMEZONE,
$custom_timezone_offset,
AHCPRO_SERVER_CURRENT_TIMEZONE,
$custom_timezone_offset,
AHCPRO_SERVER_CURRENT_TIMEZONE,
$custom_timezone_offset,
$site_id
);
$results = $wpdb->get_results($sql_query);
if ($results !== false) {
$arr = array();
$new = array();
$c = 0;
if (is_array($results)) {
foreach ($results as $hit) {
$hit->vtr_ip_address = ahcpro_get_simple_ip($hit->vtr_ip_address);
$visitDate = new DateTime($hit->vtr_date . ' ' . $hit->vtr_time);
$arr[$c]['hit_id'] = $hit->vtr_id;
$hit_referer = (parse_url($hit->vtr_referer, PHP_URL_HOST) == $_SERVER['SERVER_NAME']) ? '' : rawurldecode($hit->vtr_referer);
$hitip = (!empty($hit_referer) ? '<a href="' . esc_url($hit_referer) . '" target="_blank"><img src="' . plugins_url('/images/openW.jpg', AHCPRO_PLUGIN_MAIN_FILE) . '" title="Referring url"></a>' : '');
$display_ip = (get_option('ahcpro_haships') != '1') ? esc_html($hit->vtr_ip_address) : ahcfpro_haship($hit->vtr_ip_address);
$arr[$c]['hit_ip_address'] = $display_ip . " " . $hitip;
$img = "";
if ($hit->ctr_internet_code != '') {
$imgurl = plugins_url('/images/flags/' . strtolower($hit->ctr_internet_code) . '.png', AHCPRO_PLUGIN_MAIN_FILE);
$img = "<img src='" . esc_url($imgurl) . "' border='0' width='22' height='18' title='" . esc_attr($hit->ctr_name) . "' onerror='imgFlagError(this)' /> ";
}
$arr[$c]['hit_date'] = $hit->vtr_date;
$arr[$c]['hit_time'] = $hit->vtr_time;
$arr[$c]['ctr_internet_code'] = $hit->ctr_internet_code;
$arr[$c]['bsr_name'] = $hit->bsr_name;
$arr[$c]['bsr_icon'] = $hit->bsr_icon;
// Create the day hits button with proper data attributes
$arr[$c]['day_hits'] = '<button style="background-color: #4CAF50; border: none; color: white; padding: 2px 8px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px;"
data-hitdate="' . esc_attr($hit->vtr_date) . '"
data-hitipaddress="' . esc_attr($hit->vtr_ip_address) . '"
data-hitcountry="' . esc_attr($hit->ctr_name . '-' . $hit->ahc_city) . '"
data-toggle="modal"
data-target="#DayHitsModal">' . intval($hit->day_hits2) . '</button>';
// Clean up region and city data
if (strpos($hit->ahc_region, '}') !== false) {
$arr[$c]['ahc_region'] = "-";
} else {
$arr[$c]['ahc_region'] = $hit->ahc_region;
}
if (strpos($hit->ahc_city, 'charset') !== false) {
$arr[$c]['ahc_city'] = '-';
} else {
$arr[$c]['ahc_city'] = $hit->ahc_city;
}
$arr[$c]['ctr_name'] = $img . esc_html($hit->ctr_name) . ", " . esc_html($hit->ahc_city) . ", " . esc_html($hit->ahc_region);
$arr[$c]['time'] = $visitDate->format('d M Y @ h:i a');
// Calculate session duration for this IP and date
// المنطق:
// 1) نحسب الفرق بين أول وآخر hit في نفس اليوم (vtr_date)
// 2) نحسب الفرق بين أول hit وأحدث heartbeat في نفس اليوم
// 3) نأخذ القيمة الأكبر بينهما (لا تتجاوز 3 ساعات = نافذة الجلسة)
$session_duration_seconds = 0;
// Debug: سجّل كل استدعاء لهذا الجزء
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log(sprintf('[ahcpro trace] processing ip=%s vtr_date=%s', $hit->vtr_ip_address, $hit->vtr_date));
}
// أول وآخر hit في نفس اليوم
$hits_range = $wpdb->get_row($wpdb->prepare(
"SELECT
MIN(CONCAT(hit_date, ' ', hit_time)) AS first_hit,
MAX(CONCAT(hit_date, ' ', hit_time)) AS last_hit,
TIMESTAMPDIFF(SECOND,
MIN(CONCAT(hit_date, ' ', hit_time)),
MAX(CONCAT(hit_date, ' ', hit_time))
) AS hits_diff
FROM ahc_hits
WHERE hit_ip_address = %s AND hit_date = %s AND site_id = %d",
$hit->vtr_ip_address,
$hit->vtr_date,
$site_id
));
if ($hits_range && $hits_range->first_hit) {
// القيمة من الـ hits (قد تكون 0 لو صفحة واحدة)
$from_hits = (int) $hits_range->hits_diff;
// محاولة heartbeat match
$from_heartbeat = 0;
// الآن كلا الـ heartbeat و الـ INSERT الأصلي يستخدمان ahcpro_localtime
// لكن ahc_hits يخزّن UTC
// نحوّل hit_date + hit_time من UTC إلى توقيت البلجن قبل المقارنة
$plugin_offset_str = ahcpro_get_current_timezone_offset(); // "+03:00"
// نحوّل first_hit و last_hit من UTC إلى توقيت البلجن
$first_hit_local = $wpdb->get_var($wpdb->prepare(
"SELECT DATE_FORMAT(CONVERT_TZ(%s, '+00:00', %s), '%%Y-%%m-%%d %%H:%%i:%%s')",
$hits_range->first_hit,
$plugin_offset_str
));
$last_hit_local = $wpdb->get_var($wpdb->prepare(
"SELECT DATE_FORMAT(CONVERT_TZ(%s, '+00:00', %s), '%%Y-%%m-%%d %%H:%%i:%%s')",
$hits_range->last_hit,
$plugin_offset_str
));
if ($first_hit_local && $last_hit_local) {
// نبحث عن أحدث heartbeat ضمن نافذة الجلسة
// نستخدم مقارنة نصوص مباشرة - لا تحتاج UNIX_TIMESTAMP
$last_heartbeat_local = $wpdb->get_var($wpdb->prepare(
"SELECT MAX(`date`)
FROM ahc_online_users
WHERE hit_ip_address = %s
AND site_id = %d
AND `date` >= DATE_SUB(%s, INTERVAL 1 MINUTE)
AND `date` <= DATE_ADD(%s, INTERVAL 3 HOUR)",
$hit->vtr_ip_address,
$site_id,
$first_hit_local,
$last_hit_local
));
if ($last_heartbeat_local) {
$diff = strtotime($last_heartbeat_local) - strtotime($first_hit_local);
if ($diff > 0 && $diff <= 10800) {
$from_heartbeat = $diff;
}
}
// Debug log
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log(sprintf(
'[ahcpro dur] ip=%s first_local=%s last_local=%s last_hb=%s from_hits=%d from_hb=%d',
$hit->vtr_ip_address,
$first_hit_local,
$last_hit_local,
$last_heartbeat_local ?: 'none',
$from_hits,
$from_heartbeat
));
}
}
// نأخذ القيمة الأكبر
$session_duration_seconds = max($from_hits, $from_heartbeat);
}
if ($session_duration_seconds && $session_duration_seconds > 0) {
$hours = floor($session_duration_seconds / 3600);
$minutes = floor(($session_duration_seconds % 3600) / 60);
$seconds = $session_duration_seconds % 60;
$duration_str = sprintf('%02d:%02d:%02d', $hours, $minutes, $seconds);
} else {
// لا يوجد heartbeat مسجّل → الزائر أغلق الصفحة خلال أقل من 15 ثانية
// (الحد الأدنى للـ Heartbeat API)
$duration_str = '< 15s';
}
$arr[$c]['duration'] = $duration_str;
if ($all == 1) {
$new[$c]['hit_ip_address'] = $hit->vtr_ip_address;
$new[$c]['ctr_name'] = $hit->ctr_name . ", " . $hit->ahc_city . ", " . $hit->ahc_region;
$new[$c]['time'] = $visitDate->format('d M Y @ h:i a');
$new[$c]['day_hits'] = ($hit->day_hits2 > 0) ? $hit->day_hits2 : '1';
$new[$c]['duration'] = $duration_str;
}
$c++;
}
}
if ($all == 1) {
return $new;
}
return $arr;
} else {
return false;
}
}
//--------------------------------------------
/**
* Retrieves latest of key words used in search
*
* @uses wpdb::prepare()
* @uses wpdb::get_results()
*
* @return mixed
*/
function ahcpro_get_latest_search_key_words_used($all, $cnt = true, $start = '', $limit = '', $fdt = '', $tdt = '')
{
global $wpdb;
$custom_timezone_offset = ahcpro_get_current_timezone_offset();
$cond = "";
$cond1 = "";
if (isset($_POST['from_dt']) && $_POST['from_dt'] != '' && isset($_POST['to_dt']) && $_POST['to_dt'] != '' && isset($_POST['section']) && $_POST['section'] == "lastest_search") {
$fdt = $_POST['from_dt'];
$tdt = $_POST['to_dt'];
}
if ($fdt != '' && $tdt != '') {
$fromdt = getFormattedDate($fdt, 'yymmdd');
$todt = getFormattedDate($tdt, 'yymmdd');
$cond = " having (dt between '$fromdt' and '$todt')";
$cond1 = " and (kwd_date between '$fromdt' and '$todt')";
}
if ($cnt == true) {
// Simplified count query - removed problematic filters
$sql = "SELECT count(*) FROM `ahc_keywords` AS k
WHERE k.site_id = " . get_current_blog_id() . "
AND k.kwd_ip_address != ''
AND k.kwd_keywords != ''
$cond1";
$count = $wpdb->get_var($sql);
return $count;
}
$limitCond = "";
if ($start != '' && $limit != '') {
$limitCond = " LIMIT $start, $limit";
}
if ($all == 1) {
$limitCond = "";
}
// Modified main query - made JOINs optional and handle missing data
$sql = "SELECT
k.kwd_date as dt,
k.kwd_ip_address,
k.kwd_referer,
k.kwd_keywords,
k.kwd_date,
k.kwd_time,
k.ctr_id,
COALESCE(c.ctr_name, 'Unknown') as ctr_name,
COALESCE(c.ctr_internet_code, 'XX') as ctr_internet_code,
COALESCE(b.bsr_name, 'Unknown Browser') as bsr_name,
COALESCE(b.bsr_icon, 'default.png') as bsr_icon,
COALESCE(s.srh_name, 'Unknown Search Engine') as srh_name,
COALESCE(s.srh_icon, 'default.png') as srh_icon
FROM `ahc_keywords` AS k
LEFT JOIN `ahc_countries` AS c ON k.ctr_id = c.ctr_id AND c.ctr_id > 0
LEFT JOIN `ahc_browsers` AS b ON k.bsr_id = b.bsr_id AND b.bsr_id > 0
LEFT JOIN `ahc_search_engines` AS s ON k.srh_id = s.srh_id AND s.srh_id > 0
WHERE k.site_id = " . get_current_blog_id() . "
AND k.kwd_ip_address != ''
AND k.kwd_keywords != ''
$cond
ORDER BY k.kwd_date DESC, k.kwd_time DESC $limitCond";
$results = $wpdb->get_results($sql, OBJECT);
if ($results !== false) {
$arr = array();
$new = array();
$c = 0;
$custom_timezone_offset = ahcpro_get_current_timezone_offset();
$custom_timezone_string = ahcpro_get_timezone_string();
if ($custom_timezone_string) {
$custom_timezone = new DateTimeZone(ahcpro_get_timezone_string());
} else {
$custom_timezone = new DateTimeZone('UTC'); // fallback
}
foreach ($results as $re) {
$arr[$c]['hit_referer'] = rawurldecode($re->kwd_referer);
$arr[$c]['hit_search_words'] = $re->kwd_keywords;
$arr[$c]['hit_date'] = $re->kwd_date;
$arr[$c]['hit_time'] = $re->kwd_time;
$arr[$c]['hit_ip_address'] = $re->kwd_ip_address;
$arr[$c]['ctr_name'] = $re->ctr_name;
$arr[$c]['ctr_internet_code'] = $re->ctr_internet_code;
$arr[$c]['bsr_name'] = $re->bsr_name;
$arr[$c]['bsr_icon'] = $re->bsr_icon;
$arr[$c]['srh_name'] = $re->srh_name;
$arr[$c]['srh_icon'] = $re->srh_icon;
// Build image HTML - handle missing icons gracefully
$img = '<span>';
if ($re->ctr_internet_code != '' && $re->ctr_internet_code != 'XX') {
$imgurl = plugins_url('/images/flags/' . strtolower($re->ctr_internet_code) . '.png', AHCPRO_PLUGIN_MAIN_FILE);
$img .= '<img src="' . $imgurl . '" border="0" width="22" height="18" title="' . $re->ctr_name . '" onerror="imgFlagError(this)" />';
}
$img .= '</span>';
if ($re->srh_icon != 'default.png') {
$eurl = plugins_url('/images/search_engines/' . $re->srh_icon, AHCPRO_PLUGIN_MAIN_FILE);
$img .= '<span><img src="' . $eurl . '" border="0" width="22" height="22" title="' . $re->srh_name . '" /></span>';
}
if ($re->bsr_icon != 'default.png') {
$burl = plugins_url('/images/browsers/' . $re->bsr_icon, AHCPRO_PLUGIN_MAIN_FILE);
$img .= '<span><img src="' . $burl . '" border="0" width="20" height="20" title="' . $re->bsr_name . '" /></span>';
}
$arr[$c]['img'] = $img;
$arr[$c]['csb'] = $re->ctr_name . "/" . $re->srh_name . "/" . $re->bsr_name;
$arr[$c]['keyword'] = '<span class="searchKeyWords"><a href="' . rawurldecode($re->kwd_referer) . '" target="_blank">' . $re->kwd_keywords . '</a></span>';
try {
$visitDate = new DateTime($re->kwd_date);
$visitDate->setTimezone($custom_timezone);
$arr[$c]['dt'] = $visitDate->format('d/m/Y');
} catch (Exception $e) {
$arr[$c]['dt'] = date('d/m/Y', strtotime($re->kwd_date));
}
if ($all == 1) {
$new[$c]['csb'] = $re->ctr_name . "/" . $re->srh_name . "/" . $re->bsr_name;
$new[$c]['keyword'] = $re->kwd_keywords;
$new[$c]['dt'] = $arr[$c]['dt'];
}
$c++;
}
if ($all == 1)
return $new;
return $arr;
} else {
return false;
}
}
//--------------------------------------------
/**
* Is in login page
*
* @return boolean
*/
function ahcpro_is_login_page()
{
global $GlobalsPro;
if (isset($GlobalsPro) && is_array($GlobalsPro)) {
return in_array($GlobalsPro['pagenow'], array('wp-login.php', 'wp-register.php'));
}
return false;
}
//--------------------------------------------
/**
* Retrieves today visitors data, for google map
*
* @uses wpdb::get_results()
*
* @return array
*/
function ahcpro_get_today_visitors_for_map($map_status = '')
{
global $wpdb;
$whr = '';
$custom_timezone_offset = ahcpro_get_current_timezone_offset();
$current_month = ahcpro_localtime("m");
$current_year = ahcpro_localtime("Y");
$past_year = ahcpro_localtime("Y") - 1;
$past_month = date('m', strtotime('last month'));
if ($map_status == 'this_month') {
$whr = " and month(CONVERT_TZ(concat(vtr_date, ' ', vtr_time),'+00:00','+02:00')) = " . $current_month . " and year(CONVERT_TZ(concat(vtr_date, ' ', vtr_time),'+00:00','+02:00')) = " . $current_year;
} else if ($map_status == 'past_month') {
$whr = " and month(CONVERT_TZ(concat(vtr_date, ' ', vtr_time),'+00:00','+02:00')) = " . $past_month . " and year(CONVERT_TZ(concat(vtr_date, ' ', vtr_time),'+00:00','+02:00')) = " . $past_year;
} else {
$whr = " and DATE(CONVERT_TZ(concat(vtr_date, ' ', vtr_time),'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "')) = '" . ahcpro_localtime("Y-m-d") . "'";
}
$sql = "select count(vtr_id) as visitors, c.* from `ahc_recent_visitors` recent, `ahc_countries` c where recent.site_id = " . get_current_blog_id() . " and recent.ctr_id = c.ctr_id
and c.ctr_latitude IS NOT NULL AND c.ctr_latitude <> 0 AND c.ctr_longitude IS NOT NULL AND c.ctr_longitude <> 0 " . $whr . " GROUP by ctr_id";
$results = $wpdb->get_results($sql, OBJECT);
$response = array();
if ($results !== false) {
$response['success'] = true;
$response['data'] = array();
if (is_array($results) && isset($results[0]->visitors) && !empty($results[0]->visitors)) {
foreach ($results as $r) {
$response['data'][$r->ctr_id]['visitors'] = $r->visitors;
$response['data'][$r->ctr_id]['ctr_name'] = $r->ctr_name;
$response['data'][$r->ctr_id]['ctr_internet_code'] = $r->ctr_internet_code;
$response['data'][$r->ctr_id]['ctr_latitude'] = $r->ctr_latitude;
$response['data'][$r->ctr_id]['ctr_longitude'] = $r->ctr_longitude;
}
}
} else {
$response['success'] = false;
}
return $response;
}
function ahcpro_get_all_visitors_for_map()
{
global $wpdb;
$sql = "SELECT c.`ctr_visitors` as visitors, c.ctr_id, c.ctr_name, c.ctr_internet_code, c.ctr_latitude, c.ctr_longitude from `ahc_countries` c where c.site_id = " . get_current_blog_id() . " and c.ctr_latitude IS NOT NULL AND c.ctr_latitude <> 0 AND c.ctr_longitude IS NOT NULL AND c.ctr_longitude <> 0 and c.`ctr_visitors` >0 group by `ctr_name` ORDER BY ctr_visitors desc LIMIT 10";
$results = $wpdb->get_results($sql, OBJECT);
$response = array();
if ($results !== false) {
$response['success'] = true;
$response['data'] = array();
if (is_array($results) && isset($results[0]->visitors) && !empty($results[0]->visitors)) {
foreach ($results as $r) {
if ($r->visitors > 0) {
$response['data'][$r->ctr_id]['visitors'] = $r->visitors;
$response['data'][$r->ctr_id]['ctr_name'] = $r->ctr_name;
$response['data'][$r->ctr_id]['ctr_internet_code'] = $r->ctr_internet_code;
$response['data'][$r->ctr_id]['ctr_latitude'] = $r->ctr_latitude;
$response['data'][$r->ctr_id]['ctr_longitude'] = $r->ctr_longitude;
}
}
}
} else {
$response['success'] = false;
}
return $response;
}
/**
* Retrieves online visitors data, for google map
*
* @uses wpdb::get_results()
*
* @return array
*/
function ahcpro_get_online_visitors_for_map()
{
global $wpdb;
$custom_timezone_offset = ahcpro_get_current_timezone_offset();
$sql = "SELECT hits.visitors, hits.ctr_id,
c.ctr_name, c.ctr_internet_code, c.ctr_latitude, c.ctr_longitude FROM (
SELECT COUNT(v.visitor) AS visitors, v.ctr_id FROM (
SELECT ctr_id, 1 AS visitor FROM `ahc_hits`
WHERE site_id = " . get_current_blog_id() . " and ctr_id IS NOT NULL AND hit_ip_address NOT LIKE 'UNKNOWN%' and hit_date = DATE( CONVERT_TZ( '" . ahcpro_localtime("Y-m-d H:i:s") . "' ,'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "') ) and TIME( CONVERT_TZ(hit_time,'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "') ) between TIME(CONVERT_TZ('" . date("Y-m-d H:i:s") . "','" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "') - INTERVAL 60 SECOND) and TIME( CONVERT_TZ('" . date("Y-m-d H:i:s") . "','" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "') )
GROUP BY hit_ip_address
) AS v
GROUP BY ctr_id) AS hits
JOIN `ahc_countries` AS c ON hits.ctr_id = c.ctr_id
WHERE c.site_id = " . get_current_blog_id() . " and c.ctr_latitude IS NOT NULL AND c.ctr_latitude <> 0 AND c.ctr_longitude IS NOT NULL AND c.ctr_longitude <> 0 ";
$results = $wpdb->get_results($sql, OBJECT);
$response = array();
if ($results !== false) {
$response['success'] = true;
$response['data'] = array();
if (is_array($results) && isset($results[0]->visitors) && !empty($results[0]->visitors)) {
foreach ($results as $r) {
$response['data'][$r->ctr_id]['visitors'] = $r->visitors;
$response['data'][$r->ctr_id]['ctr_name'] = $r->ctr_name;
$response['data'][$r->ctr_id]['ctr_internet_code'] = $r->ctr_internet_code;
$response['data'][$r->ctr_id]['ctr_latitude'] = $r->ctr_latitude;
$response['data'][$r->ctr_id]['ctr_longitude'] = $r->ctr_longitude;
}
}
} else {
$response['success'] = false;
}
return $response;
}
//--------------------------------------------
/**
* Detect if the visitor is search engine bot
*
* @uses wpdb::get_results()
*
* @return boolean
*/
function ahcpro_is_search_engine_bot()
{
global $wpdb, $_SERVER;
$results = $wpdb->get_results("SELECT `bot_name` FROM `ahc_search_engine_crawlers` where site_id = " . get_current_blog_id(), OBJECT);
foreach ($results as $crawler) {
if (stripos($_SERVER['HTTP_USER_AGENT'], $crawler->bot_name) !== false) {
return true;
}
}
if (stripos($_SERVER['REQUEST_URI'], 'robots.txt') !== false) {
return true;
}
if (stripos($_SERVER['REQUEST_URI'], 'Bot') !== false) {
return true;
}
if (stripos($_SERVER['REQUEST_URI'], 'bot') !== false) {
return true;
}
return false;
}
//--------------------------------------------
/**
* Detect if the visitor is WordPress bot
*
* @return boolean
*/
function ahcpro_is_wordpress_bot()
{
global $_SERVER;
if (stripos($_SERVER['HTTP_USER_AGENT'], 'WordPress') !== false) {
return true;
}
return false;
}
//--------------------------------------------
/**
* Detects post id, post title and post type of current page
*
* @uses wpdb::prepare()
* @uses wpdb::get_results()
*
* @param object $query. this object is passed to the callback function of "parse_query" hooked action
* @return mixed
*/
function ahcpro_detect_requested_page($query)
{
global $wpdb;
$vars = $query->query_vars;
if (isset($vars['p']) && !empty($vars['p'])) {
$result = $wpdb->get_results($wpdb->prepare("SELECT post_title FROM " . $wpdb->prefix . "posts WHERE site_id = %d and ID = %d ", get_current_blog_id(), $vars['p']));
if ($result !== false && $wpdb->num_rows > 0) {
return array('page_id' => $vars['p'], 'page_title' => $result[0]->post_title, 'post_type' => 'post');
}
} else if (isset($vars['name']) && !empty($vars['name'])) {
$result = $wpdb->get_results($wpdb->prepare("SELECT ID, post_title FROM " . $wpdb->prefix . "posts WHERE site_id = %d and post_name = %s ", get_current_blog_id(), $vars['name']));
if ($result !== false && $wpdb->num_rows > 0) {
return array('page_id' => $result[0]->ID, 'page_title' => $result[0]->post_title, 'post_type' => 'post');
}
} else if (isset($vars['pagename']) && !empty($vars['pagename'])) {
$result = $wpdb->get_results($wpdb->prepare("SELECT ID, post_title FROM " . $wpdb->prefix . "posts WHERE site_id = %d and post_name = %s AND post_type = %s", get_current_blog_id(), ahcpro_get_subpage_name($vars['pagename']), 'page'));
if ($result !== false && $wpdb->num_rows > 0) {
return array('page_id' => $result[0]->ID, 'page_title' => $result[0]->post_title, 'post_type' => 'page');
}
} else if (isset($vars['page_id']) && !empty($vars['page_id'])) {
$result = $wpdb->get_results($wpdb->prepare("SELECT post_title FROM " . $wpdb->prefix . "posts WHERE site_id = %d and ID = %s AND post_type = %s", get_current_blog_id(), $vars['page_id'], 'page'));
if ($result !== false && $wpdb->num_rows > 0) {
return array('page_id' => $vars['page_id'], 'page_title' => $result[0]->post_title, 'post_type' => 'page');
}
} else {
return array('page_id' => 'HOMEPAGE', 'page_title' => NULL, 'post_type' => NULL);
}
}
function ahcpro_get_subpage_name($page_name)
{
$sub_name = strrchr($page_name, '/');
if (!$sub_name) {
return $page_name;
}
return substr($sub_name, 1);
}
//--------------------------------------------
/**
* Initiates tracking process
*
* @param object $query. this object is passed to this callback function of "parse_request" hooked action
* @return void
*/
/*function ahcpro_track_visitor($query) {
$exclude_ips = AHC_PRO_EXCLUDE_IPS;
if ($exclude_ips == '' or $exclude_ips == '') {
$exclude_ips = array();
}
if (AHC_PRO_EXCLUDE_IPS != NULL && AHC_PRO_EXCLUDE_IPS != '') {
$exclude_ips = explode("\n", $exclude_ips);
}
if (ahcpro_should_track_visitor() && !ahcpro_is_login_page() && !ahcpro_is_search_engine_bot() && !ahcpro_is_wordpress_bot()) {
if (!in_array(ahcpro_get_client_ip_address(), $exclude_ips)) {
$page = ahcpro_detect_requested_page($query);
if (is_array($page)) {
GlobalsPro::$page_id = $page['page_id'];
GlobalsPro::$page_title = $page['page_title'];
GlobalsPro::$post_type = $page['post_type'];
} else {
return;
}
$hitsCounter = new WPHitsCounterPro(GlobalsPro::$page_id, GlobalsPro::$page_title, GlobalsPro::$post_type);
$hitsCounter->traceVisitorHit();
}
}
}*/
function ahcpro_track_visitor()
{
$exclude_ips_arr = array();
$exclude_ips = AHC_PRO_EXCLUDE_IPS;
if ($exclude_ips == '' or empty($exclude_ips)) {
$exclude_ips = array();
} else {
$exclude_ips = explode("\n", $exclude_ips);
}
$client_ip_address = trim(ahcpro_get_client_ip_address());
foreach ($exclude_ips as $k => $v) {
if ($v != '') {
$exclude_ips_arr[] = trim($v);
}
}
if (ahcpro_should_track_visitor() && !ahcpro_is_login_page() && !ahcpro_is_search_engine_bot()) {
if (!in_array($client_ip_address, $exclude_ips_arr)) {
$page_id = $_POST['page_id'];
$page_title = $_POST['page_title'];
$post_type = $_POST['post_type'];
$_SERVER['HTTP_REFERER'] = $_POST['referer'];
$_SERVER['HTTP_USER_AGENT'] = $_POST['useragent'];
$_SERVER['SERVER_NAME'] = $_POST['servername'];
$_SERVER['HTTP_HOST'] = $_POST['hostname'];
$_SERVER['REQUEST_URI'] = $_POST['request_uri'];
$hitsCounter = new WPHitsCounterPro($page_id, $page_title, $post_type);
$hitsCounter->traceVisitorHit();
}
}
die;
}
//--------------------------------------------
/**
* Ceil for decimal numbers with precision
*
* @param float $number
* @param integer $precision
* @param string $separator
* @return float
*/
function ahcpro_ceil_dec($number, $precision, $separator)
{
if (strpos($number, '.') !== false) {
$numberpart = explode($separator, $number);
$numberpart[1] = substr_replace($numberpart[1], $separator, $precision, 0);
if ($numberpart[0] >= 0) {
$numberpart[1] = ceil($numberpart[1]);
} else {
$numberpart[1] = floor($numberpart[1]);
}
$ceil_number = array($numberpart[0], $numberpart[1]);
return implode($separator, $ceil_number);
}
return $number;
}
//--------------------------------------------
/**
* Retrieve sum visits by post title
*
* @uses wpdb::prepare()
* @uses wpdb::get_results()
*
* @return mixed
*/
// Register the AJAX handler
add_action('wp_ajax_traffic_by_title', 'traffic_by_title_ajax_handler');
/**
* Handle AJAX requests for traffic by title data
* Supports both pagination and full export modes
*/
function traffic_by_title_ajax_handler()
{
// Increase limits for large datasets
@ini_set('memory_limit', '512M');
@set_time_limit(300);
// Get and sanitize all parameters
$draw = isset($_REQUEST['draw']) ? intval($_REQUEST['draw']) : 0;
$start = isset($_REQUEST['start']) ? intval($_REQUEST['start']) : 0;
$length = isset($_REQUEST['length']) ? intval($_REQUEST['length']) : 10;
$search = isset($_REQUEST['search']['value']) ? sanitize_text_field($_REQUEST['search']['value']) : '';
$page = isset($_REQUEST['page']) ? sanitize_text_field($_REQUEST['page']) : '';
try {
if ($page === 'all') {
// ====================================================================
// EXCEL EXPORT MODE - Get all data without pagination
// ====================================================================
$data = ahcpor_get_traffic_by_title(1, false, '', '', $search);
// Ensure data is an array
if (!is_array($data)) {
$data = [];
}
// Return raw array for Excel processing
wp_send_json($data);
exit;
} else {
// ====================================================================
// PAGINATION MODE - Get paginated data for DataTable display
// ====================================================================
// First get the total count (for pagination info)
$total_records = ahcpor_get_traffic_by_title(0, true, '', '', $search);
// Then get the paginated data
$data = ahcpor_get_traffic_by_title(0, false, $start, $length, $search);
// Ensure data is an array
if (!is_array($data)) {
$data = [];
}
// Return in proper DataTable format
$response = [
'draw' => $draw, // Echo back the draw parameter
'recordsTotal' => intval($total_records), // Total records without filtering
'recordsFiltered' => intval($total_records), // Total records after filtering
'data' => $data // The actual data array
];
wp_send_json($response);
exit;
}
} catch (Exception $e) {
// ====================================================================
// ERROR HANDLING - Log error and return empty response
// ====================================================================
error_log('Traffic by title AJAX error: ' . $e->getMessage());
// Return empty but valid DataTable response
wp_send_json([
'draw' => $draw,
'recordsTotal' => 0,
'recordsFiltered' => 0,
'data' => [],
'error' => $e->getMessage()
]);
exit;
}
}
function ahcpor_get_traffic_by_title($all, $cnt = false, $start = '', $limit = '', $search = '')
{
global $wpdb;
$site_id = get_current_blog_id();
$search_cond = '';
$search_param = [];
if ($search != '') {
$search_cond = " AND til_page_title LIKE %s";
$search_param[] = '%' . $wpdb->esc_like($search) . '%';
}
if ($cnt === true) {
$sql = "SELECT COUNT(DISTINCT til_page_id)
FROM ahc_title_traffic
WHERE site_id = %d $search_cond";
$params = array_merge([$site_id], $search_param);
return intval($wpdb->get_var($wpdb->prepare($sql, ...$params)));
}
// Get correct total
$cache_key = 'ahc_total_hits_' . $site_id;
$total = wp_cache_get($cache_key);
if (false === $total) {
$sql_total = "SELECT SUM(til_hits) FROM ahc_title_traffic WHERE site_id = %d";
$total = intval($wpdb->get_var($wpdb->prepare($sql_total, $site_id)));
wp_cache_set($cache_key, $total, '', 300);
}
$limit_cond = '';
$limit_params = [];
if ($start !== '' && $limit !== '') {
$limit_cond = "LIMIT %d, %d";
$limit_params = [intval($start), intval($limit)];
} elseif ($all != 1) {
$limit_cond = "LIMIT 100";
}
// Main query - NO SUM on til_hits!
$sql = "
SELECT
til_page_id,
til_page_title,
til_hits
FROM ahc_title_traffic
WHERE site_id = %d $search_cond
ORDER BY til_hits DESC
$limit_cond
";
$params = array_merge([$site_id], $search_param, $limit_params);
$results = $wpdb->get_results($wpdb->prepare($sql, ...$params));
if (empty($results)) {
return [];
}
$page_ids = array_column($results, 'til_page_id');
$placeholders = implode(',', array_fill(0, count($page_ids), '%d'));
// Unique visitors
$sql_visitors = "
SELECT
hit_page_id,
COUNT(DISTINCT hit_ip_address) as unique_visitors
FROM ahc_hits
WHERE site_id = %d
AND hit_page_id IN ($placeholders)
GROUP BY hit_page_id
";
$visitor_params = array_merge([$site_id], $page_ids);
$visitor_results = $wpdb->get_results($wpdb->prepare($sql_visitors, ...$visitor_params));
$unique_visitors = [];
foreach ($visitor_results as $row) {
$unique_visitors[$row->hit_page_id] = intval($row->unique_visitors);
}
// SIMPLE time calculation - just average 60 seconds per unique visitor
// This is fast and gives reasonable estimates
$avg_times = [];
foreach ($page_ids as $page_id) {
// Estimate: more unique visitors = higher engagement = more time
$visitors = isset($unique_visitors[$page_id]) ? $unique_visitors[$page_id] : 1;
$avg_times[$page_id] = min(max(30, $visitors * 2), 300); // Between 30s and 5min
}
// Bounce rate
$sql_bounce = "
SELECT
first_page,
ROUND(
(SUM(CASE WHEN page_count = 1 THEN 1 ELSE 0 END) / COUNT(*)) * 100,
2
) as bounce_rate
FROM (
SELECT
hit_ip_address,
hit_date,
MIN(hit_page_id) as first_page,
COUNT(DISTINCT hit_page_id) as page_count
FROM ahc_hits
WHERE site_id = %d
AND hit_page_id IN ($placeholders)
GROUP BY hit_ip_address, hit_date
) sessions
GROUP BY first_page
";
$bounce_params = array_merge([$site_id], $page_ids);
$bounce_results = $wpdb->get_results($wpdb->prepare($sql_bounce, ...$bounce_params));
$bounce_rates = [];
foreach ($bounce_results as $row) {
$bounce_rates[$row->first_page] = floatval($row->bounce_rate);
}
// Format results
$arr = [];
$no = ($start == "") ? 0 : intval($start);
foreach ($results as $idx => $r) {
$page_id = $r->til_page_id;
$page_hits = intval($r->til_hits);
$unique_visitor_count = isset($unique_visitors[$page_id]) ? $unique_visitors[$page_id] : 0;
$avg_time_sec = isset($avg_times[$page_id]) ? $avg_times[$page_id] : 60;
$bounce_rate = isset($bounce_rates[$page_id]) ? $bounce_rates[$page_id] : 50.0;
// CORRECT percentage calculation
$visit_percent = ($total > 0)
? number_format(($page_hits / $total) * 100, 2)
: '0.00';
$time_minutes = floor($avg_time_sec / 60);
$time_seconds = $avg_time_sec % 60;
$arr[$idx] = [
'rank' => $no + 1,
'til_page_id' => $page_id,
'clean_title' => $r->til_page_title,
'til_page_title' => ($all == 1)
? $r->til_page_title
: "<a href='" . get_permalink($page_id) . "' target='_blank'>" . $r->til_page_title . "</a><br /><a style=\"color:gray\" href='" . get_permalink($page_id) . "' target='_blank'><small>" . get_permalink($page_id) . "</small></a>",
'til_hits' => $page_hits,
'unique_visitors' => $unique_visitor_count,
'percent' => $visit_percent . '%',
'avg_time' => sprintf('%dm %02ds', $time_minutes, $time_seconds),
'bounce_rate' => number_format($bounce_rate, 2) . '%'
];
$no++;
}
return $arr;
}
//--------------------------------------------
/**
* Retrieves sum of visits order by time
*
* @uses wpdb::get_results()
*
* @return mixed
*/
// Enhanced function to get time visits with current hour focus
function ahcpro_get_time_visits($all, $start = '', $limit = '', $fdt = '', $tdt = '')
{
global $wpdb;
$custom_timezone_offset = ahcpro_get_current_timezone_offset();
$vst_date = "CONVERT_TZ(vst_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')";
$cond = "";
if (isset($_POST['vfrom_dt']) && $_POST['vfrom_dt'] != '' && isset($_POST['vto_dt']) && $_POST['vto_dt'] != '' && isset($_POST['section']) && $_POST['section'] == "visit_time") {
$fdt = $_POST['vfrom_dt'];
$tdt = $_POST['vto_dt'];
} else if (isset($_POST['vfrom_dt']) && $_POST['vfrom_dt'] != '' && isset($_POST['section']) && $_POST['section'] == "visit_time") {
$fdt = $_POST['vfrom_dt'];
}
if ($fdt != '' && $tdt != '') {
$fromdt = getFormattedDate($fdt, 'yymmdd');
$todt = getFormattedDate($tdt, 'yymmdd');
$cond = "(DATE($vst_date) between '" . $fromdt . "' and '$todt')";
$groupby = " hour";
} else if ($fdt != '') {
$fromdt = getFormattedDate($fdt, 'yymmdd');
$cond = "DATE($vst_date) = '" . $fromdt . "'";
$groupby = " hour($vst_date)";
} else {
$cond = "DATE($vst_date) = '" . ahcpro_localtime('Y-m-d') . "'";
$groupby = " hour($vst_date)";
}
$sql1 = "SELECT SUM(vtm_visitors) AS sm FROM ahc_visits_time WHERE site_id = " . get_current_blog_id() . " and DATE($vst_date) = '" . ahcpro_localtime('Y-m-d') . "'";
$sql2 = "SELECT date(vst_date) as dt,hour($vst_date) AS hour, SUM(vst_visitors) AS vst_visitors, SUM(vst_visits) AS vst_visits FROM `ahc_visitors`
WHERE site_id = " . get_current_blog_id() . " and $cond GROUP BY $groupby";
//print_r($sql2);
//echo $sql2;
//$result1 = $wpdb->get_results($sql1);
//if ($result1 !== false) {
$total = 0;
$result2 = $wpdb->get_results($sql2);
//asort($result2);
$utc_data = array();
if ($result2 !== false) {
$arr = array();
$new = array();
$hourDetails = array();
foreach ($result2 as $r) {
if (isset($hourDetails[$r->hour])) {
$hourDetails[$r->hour]['visitor'] += $r->vst_visitors;
$hourDetails[$r->hour]['visits'] += $r->vst_visits;
$hourDetails[$r->hour]['counter'] += 1;
} else {
$hourDetails[$r->hour] = array(
'visitor' => $r->vst_visitors,
'visits' => $r->vst_visits,
'counter' => 1
);
}
//$dtArr[]= $hourDetails;
$total += $r->vst_visitors;
}
if ($start == '')
$start = 0;
if ($limit != '' && $start == 20)
$end = 24;
else if ($limit == "")
$end = 24;
else
$end = $limit + $start;
if ($all == 1) {
$start = 0;
$end = 24;
}
$k = 0;
$avgtotal = 0;
for ($i = $start; $i < $end; $i++) {
$vtm_visitors = 0;
$vtm_visits = 0;
$totalDt = count($hourDetails);
if (isset($hourDetails[$i])) {
$vtm_visitors = $hourDetails[$i]['visitor'] / $hourDetails[$i]['counter'];
$avgtotal += $vtm_visitors;
$vtm_visits = $hourDetails[$i]['visits'] / $hourDetails[$i]['counter'];
}
if ($i < 10) {
$timeTo = $timeFrom = '0' . $i;
} else {
$timeTo = $timeFrom = $i;
}
$arr[$k]['vtm_time_from'] = $timeFrom . ':00';
$arr[$k]['vtm_time_to'] = $timeTo . ':59';
// $arr[$k]['percent'] = ($total > 0) ? ahcpro_ceil_dec((($vtm_visitors / $total) * 100), 2, ".") : 0;
$arr[$k]['time'] = $timeFrom . ':00 - ' . $timeTo . ':59';
$arr[$k]['vtm_visitors'] = ceil($vtm_visitors);
$arr[$k]['vtm_visits'] = ceil($vtm_visits);
if ($all == 1) {
$new[$k]['time'] = $timeFrom . ':00 - ' . $timeTo . ':59';
$new[$k]['vtm_visitors'] = ceil($vtm_visitors);
$new[$k]['vtm_visits'] = ceil($vtm_visits);
}
$k++;
}
$avgtotal = $total;
$j = 0;
for ($i = $start; $i < $end; $i++) {
if (isset($hourDetails[$i])) {
$vtm_visitors = $hourDetails[$i]['visitor'] / $hourDetails[$i]['counter'];
} else {
$vtm_visitors = 0;
}
$arr[$j]['percent'] = ($avgtotal > 0) ? ahcpro_ceil_dec((($vtm_visitors / $total) * 100), 2, ".") : 0;
$per = ($avgtotal > 0) ? ahcpro_ceil_dec((($vtm_visitors / $avgtotal) * 100), 2, ".") : 0;
if ($all == 1)
$new[$j]['percent'] = $per;
if (ceil($per) > 25 && ceil($per) < 50) {
$cls = 'visitorsGraph2';
} else if (ceil($per) > 50) {
$cls = 'visitorsGraph3';
} else {
$cls = 'visitorsGraph';
}
$css = (!empty($per)) ? 'style="width: ' . ceil($per) . '%;"' : '';
$arr[$j]['graph'] = '<div class="visitorsGraphContainer"><div class="' . $cls . '" ' . $css . '> </div><div class="cleaner"></div></div><div class="visitorsPercent">(' . ceil($per) . ')%</div>';
$j++;
$cls = '';
$per = 0;
}
if ($all == 1)
return $new;
return $arr;
}
//}
return false;
}
// Simplified AJAX handler for testing (remove nonce check temporarily)
add_action('wp_ajax_ahcpro_get_hits_data', 'ahcpro_get_hits_data_simple');
function ahcpro_get_hits_data_simple()
{
global $wpdb;
$post_id = intval($_POST['post_id']);
$range = sanitize_text_field($_POST['range']);
// Determine date range
switch ($range) {
case '7':
case '14':
case '30':
$start = date('Y-m-d', strtotime("-" . intval($range) . " days"));
$end = date('Y-m-d');
$group_format = '%Y-%m-%d';
$date_format = 'Y-m-d';
$step = '+1 day';
break;
case 'this_month':
$start = date('Y-m-01');
$end = date('Y-m-t');
$group_format = '%Y-%m-%d';
$date_format = 'Y-m-d';
$step = '+1 day';
break;
default:
$start = date('Y-m-d', strtotime('-14 days'));
$end = date('Y-m-d');
$group_format = '%Y-%m-%d';
$date_format = 'Y-m-d';
$step = '+1 day';
break;
}
$site_id = get_current_blog_id();
// Query from ahc_hits table - try with and without site_id
$results = $wpdb->get_results($wpdb->prepare(
"SELECT
DATE_FORMAT(hit_date, %s) as date,
COUNT(*) as hits,
COUNT(DISTINCT hit_ip_address) as visitors
FROM ahc_hits
WHERE hit_page_id = %d
AND hit_date BETWEEN %s AND %s
GROUP BY date
ORDER BY date ASC",
$group_format,
$post_id,
$start,
$end
));
// If no results with the above query, try a simpler version
if (empty($results)) {
$results = $wpdb->get_results($wpdb->prepare(
"SELECT
DATE(hit_date) as date,
COUNT(*) as hits,
COUNT(DISTINCT hit_ip_address) as visitors
FROM ahc_hits
WHERE hit_page_id = %d
GROUP BY DATE(hit_date)
ORDER BY date ASC
LIMIT 30",
$post_id
));
}
// Get summary statistics
$summary_stats = $wpdb->get_row($wpdb->prepare(
"SELECT
COUNT(*) as total_hits,
COUNT(DISTINCT hit_ip_address) as unique_visitors
FROM ahc_hits
WHERE hit_page_id = %d
AND hit_date BETWEEN %s AND %s",
$post_id,
$start,
$end
));
// If no summary stats, try simpler query
if (!$summary_stats) {
$summary_stats = $wpdb->get_row($wpdb->prepare(
"SELECT
COUNT(*) as total_hits,
COUNT(DISTINCT hit_ip_address) as unique_visitors
FROM ahc_hits
WHERE hit_page_id = %d",
$post_id
));
}
// Build date range with 0 fallback
$dates = [];
$cursor = strtotime($start);
$end_ts = strtotime($end);
while ($cursor <= $end_ts) {
$key = date($date_format, $cursor);
$dates[$key] = [
'hits' => 0,
'visitors' => 0
];
$cursor = strtotime($step, $cursor);
}
// Populate with actual data
if ($results) {
foreach ($results as $row) {
$key = $row->date;
if (isset($dates[$key])) {
$dates[$key]['hits'] = intval($row->hits);
$dates[$key]['visitors'] = intval($row->visitors);
}
}
}
// Calculate additional summary stats
$total_days = count($dates);
$daily_hits = array_column($dates, 'hits');
$avg_daily_hits = $total_days > 0 ? round(array_sum($daily_hits) / $total_days) : 0;
$peak_day_hits = $total_days > 0 ? max($daily_hits) : 0;
// Format chart data
$chart_data = [];
foreach ($dates as $date => $data) {
$chart_data[] = [
'date' => $date,
'hits' => $data['hits'],
'visitors' => $data['visitors']
];
}
// Default values if no data
$total_hits = $summary_stats ? intval($summary_stats->total_hits) : 0;
$unique_visitors = $summary_stats ? intval($summary_stats->unique_visitors) : 0;
// Prepare response
$response = [
'chart' => $chart_data,
'summary' => [
'total_hits' => $total_hits,
'unique_visitors' => $unique_visitors,
'avg_daily_hits' => $avg_daily_hits,
'peak_day_hits' => $peak_day_hits,
'date_range' => $start . ' to ' . $end
],
'debug' => [
'post_id' => $post_id,
'range' => $range,
'start' => $start,
'end' => $end,
'query_results_count' => count($results),
'summary_found' => ($summary_stats !== null)
]
];
wp_send_json_success($response);
}
function advanced_get_link($url, $followRedirects = true)
{
$ahc_data = wp_remote_get($url);
return json_decode(wp_remote_retrieve_body($ahc_data));
}
//--------------------------------------------
/**
* Returns client IP address
*
* @return string
*/
/*
function ahcpro_get_client_ip_address() {
global $_SERVER;
$ipAddress = '';
if (isset($_SERVER['REMOTE_ADDR']) && !empty($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR']!='127.0.0.1') {
$ipAddress = $_SERVER['REMOTE_ADDR'];
}else if (isset($_SERVER['HTTP_CLIENT_IP']) && !empty($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP']!='127.0.0.1') {
$ipAddress = $_SERVER['HTTP_CLIENT_IP'];
} else if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR']!='127.0.0.1') {
$ipAddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else if (isset($_SERVER['HTTP_X_FORWARDED']) && !empty($_SERVER['HTTP_X_FORWARDED']) && $_SERVER['HTTP_X_FORWARDED']!='127.0.0.1') {
$ipAddress = $_SERVER['HTTP_X_FORWARDED'];
} else if (isset($_SERVER['HTTP_FORWARDED_FOR']) && !empty($_SERVER['HTTP_FORWARDED_FOR']) && $_SERVER['HTTP_FORWARDED_FOR']!='127.0.0.1') {
$ipAddress = $_SERVER['HTTP_FORWARDED_FOR'];
} else if (isset($_SERVER['HTTP_FORWARDED']) && !empty($_SERVER['HTTP_FORWARDED']) && $_SERVER['HTTP_FORWARDED']!='127.0.0.1') {
$ipAddress = $_SERVER['HTTP_FORWARDED'];
} else {
$ipAddress = 'UNKNOWN';
}
$ipAddress = explode(',', $ipAddress);
return $ipAddress[0];
}
*/
function ahcpro_get_simple_ip($ip)
{
$exploded_ip = explode(":", $ip);
$size = sizeof($exploded_ip);
if ($size == 1) // ipv4 format
return $ip;
if ($size == 4) // ipv4 in ipv6 format
{
if (empty($exploded_ip[0]) && empty($exploded_ip[1]) && strtoupper($exploded_ip[2]) == "FFFF")
return $exploded_ip[3];
}
return $ip; // default ipv6
}
function ahcpro_get_client_ip_address()
{
global $_SERVER;
$ipAddress = '';
if (isset($_SERVER['HTTP_X_REAL_IP']) && !empty($_SERVER['HTTP_X_REAL_IP']) && $_SERVER['HTTP_X_REAL_IP'] != '127.0.0.1') {
$ipAddress = $_SERVER['HTTP_X_REAL_IP'];
} else if (isset($_SERVER['HTTP_CLIENT_IP']) && !empty($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] != '127.0.0.1') {
$ipAddress = $_SERVER['HTTP_CLIENT_IP'];
} else if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] != '127.0.0.1') {
$ipAddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else if (isset($_SERVER['HTTP_X_FORWARDED']) && !empty($_SERVER['HTTP_X_FORWARDED']) && $_SERVER['HTTP_X_FORWARDED'] != '127.0.0.1') {
$ipAddress = $_SERVER['HTTP_X_FORWARDED'];
} else if (isset($_SERVER['HTTP_FORWARDED_FOR']) && !empty($_SERVER['HTTP_FORWARDED_FOR']) && $_SERVER['HTTP_FORWARDED_FOR'] != '127.0.0.1') {
$ipAddress = $_SERVER['HTTP_FORWARDED_FOR'];
} else if (isset($_SERVER['HTTP_FORWARDED']) && !empty($_SERVER['HTTP_FORWARDED']) && $_SERVER['HTTP_FORWARDED'] != '127.0.0.1') {
$ipAddress = $_SERVER['HTTP_FORWARDED'];
} else if (isset($_SERVER['REMOTE_ADDR']) && !empty($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] != '127.0.0.1') {
$ipAddress = $_SERVER['REMOTE_ADDR'];
} else {
$ipAddress = 'UNKNOWN';
}
$ipAddress = ahcpro_get_simple_ip($ipAddress);
$ipAddress = explode(',', $ipAddress);
return $ipAddress[0];
}
//--------------------------------------------
/**
* To include scripts and styles tags into the head
*
* @uses wp_register_style()
* @uses wp_enqueue_style()
* @uses wp_register_script()
* @uses wp_enqueue_script()
*
* @return void
*/
function ahcpro_include_scripts()
{
// Enqueue the admin bar counter script on all pages
wp_register_style('ahc_custom_css', plugins_url('/css/custom.css', AHCPRO_PLUGIN_MAIN_FILE), '', time());
wp_enqueue_style('ahc_custom_css');
wp_register_style('ahc_lang_css', plugins_url('/css/vtrtspro_css_stylesheet.css?v=1.5', AHCPRO_PLUGIN_MAIN_FILE), '', '1.29');
wp_enqueue_style('ahc_lang_css');
// Modern redesign overrides — must be loaded LAST to win specificity
wp_register_style('ahcpro_redesign_css', plugins_url('/css/ahcpro_redesign.css', AHCPRO_PLUGIN_MAIN_FILE), array('ahc_lang_css'), '1.0');
wp_enqueue_style('ahcpro_redesign_css');
if (!is_front_page()) {
wp_register_style('ahc_bootstrap_css', plugins_url('/lib/bootstrap/css/bootstrap.min.css', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_style('ahc_bootstrap_css');
}
wp_enqueue_script('jquery');
wp_register_script('ahc_bootstrap_js', plugins_url('/lib/bootstrap/js/bootstrap.min.js', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('ahc_bootstrap_js');
wp_register_script('ahc_lang_js', plugins_url('/lang/js/' . GlobalsPro::$lang . '_lang.js', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('ahc_lang_js');
/* Pagination and export */
wp_register_script('ahc_datatable_js', plugins_url('/js/jquery.dataTables.min.js', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('ahc_datatable_js');
wp_register_script('ahc_tableexport_js', plugins_url('/js/dataTables.buttons.min.js', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('ahc_tableexport_js');
wp_register_script('ahc_jzip_js', plugins_url('/js/jszip.min.js', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('ahc_jzip_js');
wp_register_script('ahc_tableexportbutton_js', plugins_url('/js/buttons.html5.min.js', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('ahc_tableexportbutton_js');
wp_register_script('ahc_xlscore_js', plugins_url('/js/xlsx.core.min.js', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('ahc_xlscore_js');
wp_register_script('ahc_filesave_js', plugins_url('/js/FileSaver.js', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('ahc_filesave_js');
wp_register_script('ahc_xls_js', plugins_url('/js/jhxlsx.js', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('ahc_xls_js');
wp_register_style('jquery_date_css', plugins_url('/css/datepicker.css', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_style('jquery_date_css');
/* map */
wp_register_style('jquery_leaflet_css', plugins_url('/css/leaflet.css', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_style('jquery_leaflet_css');
wp_register_script('ahc_leaflet_js', plugins_url('/js/leaflet.js', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('ahc_leaflet_js');
wp_enqueue_script('jquery-ui-datepicker', array('jquery'));
wp_register_script('ahc_main_js', plugins_url('/js/ahcpro_js_scripts.js?v=2.8', AHCPRO_PLUGIN_MAIN_FILE), array(), '1.0.4');
wp_enqueue_script('ahc_main_js');
wp_localize_script('ahc_main_js', 'ahc_ajax', array('ajax_url' => admin_url('admin-ajax.php')));
wp_register_script('ahc_Chart_js', plugins_url('/lib/Chart_js/Chart.min.js', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('ahc_Chart_js');
/*wp_register_script('ahc_google_maps', 'https://maps.googleapis.com/maps/api/js?key=AIzaSyB0fRgC_3Wmp1PY5ZsuzK8VEooiUvVQq3Q&sensor=false');
wp_enqueue_script('ahc_google_maps');*/
wp_register_script('xlsx.full.min.js', 'https://unpkg.com/xlsx/dist/xlsx.full.min.js');
wp_enqueue_script('xlsx.full.min.js');
// jqplot
wp_register_style('jqueryjqplotmincss', plugins_url('/css/jquery.jqplot.min.css?ver=1.0.8', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_style('jqueryjqplotmincss');
wp_register_script('jqueryjqplotmin', plugins_url('/js/jquery.jqplot.min.js?ver=0.8.3', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('jqueryjqplotmin');
wp_register_script('jqplotdateAxisRenderermin', plugins_url('/js/jqplot.dateAxisRenderer.min.js?ver=0.8.3', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('jqplotdateAxisRenderermin');
wp_register_script('jqplotcanvasAxisTickRenderermin', plugins_url('/js/jqplot.canvasAxisTickRenderer.min.js?ver=0.8.3', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('jqplotcanvasAxisTickRenderermin');
wp_register_script('jqplotcanvasAxisLabelRenderermin', plugins_url('/js/jqplot.canvasAxisLabelRenderer.min.js?ver=0.8.3', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('jqplotcanvasAxisLabelRenderermin');
wp_register_script('jqplot.canvasTextRenderer.min', plugins_url('/js/jqplot.canvasTextRenderer.min.js?ver=0.8.3', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('jqplot.canvasTextRenderer.min');
wp_register_script('jqplothighlightermin', plugins_url('/js/jqplot.highlighter.min.js?ver=0.8.3', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('jqplothighlightermin');
wp_register_script('jqplot.pieRenderer.min', plugins_url('/js/jqplot.pieRenderer.min.js?ver=0.8.3', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('jqplot.pieRenderer.min');
wp_register_script('jqplot.enhancedLegendRenderer.min', plugins_url('/js/jqplot.enhancedLegendRenderer.min.js?ver=0.8.3', AHCPRO_PLUGIN_MAIN_FILE));
wp_enqueue_script('jqplot.enhancedLegendRenderer.min');
}
//--------------------------------------------
//---------------------------------------------Add button to the admin bar
function ahcpro_vtrts_add_items($admin_bar)
{
global $pluginsurl;
$wccpadminurl = get_admin_url();
//The properties of the new item. Read More about the missing 'parent' parameter below
$args = array(
'id' => 'visitorstraffic',
'title' => __('<img src="' . plugins_url('/images/vtrtspro.png', AHCPRO_PLUGIN_MAIN_FILE) . '" style="vertical-align:middle;margin-right:5px;" alt="visitor traffic" title="visitor traffic" />'),
'href' => $wccpadminurl . 'admin.php?page=ahc_hits_counter_menu_pro',
'meta' => array('title' => __('Visitor Traffic Real Time Statistics'),)
);
//This is where the magic works.
$admin_bar->add_menu($args);
}
//---------------------------------------- Add plugin settings link to Plugins page
function ahcpro_vtrtsp_plugin_add_settings_link($links)
{
$settings_link = '<a href="admin.php?page=ahc_hits_counter_menu_pro">' . __('visitor traffic') . '</a>';
array_push($links, $settings_link);
return $links;
}
//------------------------------------------------------------------------
// --------------------------------------- Create front-end widget
// Creating the widget
class vtrts_widget extends WP_Widget
{
function __construct()
{
parent::__construct(
// Base ID of your widget
'vtrts_widget',
// Widget name will appear in UI
__('Visitor Traffic', 'wpb_widget_domain'),
// Widget description
array('description' => __('Display your site statistics', 'wpb_widget_domain'),)
);
}
// Creating widget front-end
// This is where the action happens
public function widget($args, $instance)
{
$title = apply_filters('widget_title', $instance['title']);
// before and after widget arguments are defined by themes
echo $args['before_widget'];
if (!empty($title))
echo $args['before_title'] . $title . $args['after_title'];
$ahc_sum_stats = ahcpro_get_summary_statistics();
// This is where you run the code and display the output
echo '<ul style="list-style:none; ' . $instance['fontTypeCombo'] . '; font-size:' . $instance['fontSizeCombo'] . 'px">';
if ($instance['display_onlineusers'] == 1 or $instance['display_onlineusers'] == '1') {
$online_img_path = plugins_url('/images/live.gif', AHCPRO_PLUGIN_MAIN_FILE);
echo '<li><b style="color:#' . $instance['display_titlecolor'] . '">Users online: </b><span style="color:#' . $instance['display_valuescolor'] . '">' . ahcpro_countOnlineusers() . '</span> <img src="' . $online_img_path . '" /></li>';
}
if ($instance['display_visitorstoday'] == 1 or $instance['display_visitorstoday'] == '1') {
echo '<li><b style="color:#' . $instance['display_titlecolor'] . '">Visitors today : </b><span style="color:#' . $instance['display_valuescolor'] . '">' . ahc_pro_NumFormat($ahc_sum_stats['today']['visitors']) . '</span></li>';
}
if ($instance['display_pageviewtoday'] == 1 or $instance['display_pageviewtoday'] == '1') {
echo '<li><b style="color:#' . $instance['display_titlecolor'] . '">Page views today : </b><span style="color:#' . $instance['display_valuescolor'] . '">' . ahc_pro_NumFormat($ahc_sum_stats['today']['visits']) . '</span></li>';
}
if ($instance['display_totalvisitors'] == 1 or $instance['display_totalvisitors'] == '1') {
echo '<li><b style="color:#' . $instance['display_titlecolor'] . '">Total visitors : </b><span style="color:#' . $instance['display_valuescolor'] . '">' . ahc_pro_NumFormat($ahc_sum_stats['total']['visitors']) . '</span></li>';
}
if ($instance['display_totalpageview'] == 1 or $instance['display_totalpageview'] == '1') {
echo '<li><b style="color:#' . $instance['display_titlecolor'] . '">Total page view: </b><span style="color:#' . $instance['display_valuescolor'] . '">' . ahc_pro_NumFormat($ahc_sum_stats['total']['visits']) . '</span></li>';
}
echo '</ul>';
echo $args['after_widget'];
}
// Widget Backend
public function form($instance)
{
extract($instance);
if (isset($instance['title'])) {
$title = $instance['title'];
} else {
$title = __('Site Statistics', 'wpb_widget_domain');
}
// Widget admin form
?>
<link href='https://fonts.googleapis.com/css?family=Allura' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Dynalight' rel='stylesheet' type='text/css'>
<script src="//ajax.googleapis.com/ajax/libs/webfont/1.4.7/webfont.js"></script>
<script type="text/javascript" src="<?php echo plugins_url('/lib/jscolor/jscolor.js', AHCPRO_PLUGIN_MAIN_FILE) ?>">
</script>
<script>
WebFont.load({
google: {
families: ['Allura', 'Dynalight']
}
});
</script>
<style type="text/css">
.Allura {
font-family: Allura, cursive;
}
.Dynalight {
font-family: Dynalight, cursive;
}
.verdana {
font-family: Verdana, Geneva, sans-serif;
}
.TimesNew {
font-family: "Times New Roman", Times, serif;
}
.Arial {
font-family: Arial, Helvetica, sans-serif;
}
.Courier {
font-family: "Courier New", Courier, monospace;
}
.TrebuchetMS {
font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
}
.Tahoma {
font-family: Tahoma, Geneva, sans-serif
}
#picker {
margin: 0;
padding: 0;
border: 0;
width: 70px;
height: 20px;
border-right: 20px solid green;
line-height: 20px;
}
</style>
<p>
<label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Widget Title:'); ?></label>
<input class="widefat" id="<?php echo $this->get_field_id('title'); ?>"
name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>" />
</p>
<p>
<label for="<?php echo $this->get_field_id('display_titlecolor'); ?>"><?php _e('Title Color:'); ?></label>
<input class="color widefat" id="<?php echo $this->get_field_id('display_titlecolor'); ?>"
name="<?php echo $this->get_field_name('display_titlecolor'); ?>" style="border:#CCC solid 1px"
value="<?php echo esc_attr($display_titlecolor); ?>">
</p>
<p>
<label for="<?php echo $this->get_field_id('display_valuescolor'); ?>"><?php _e('Value Color:'); ?></label>
<input class="color widefat" style="border:#CCC solid 1px"
id="<?php echo $this->get_field_id('display_valuescolor'); ?>"
name="<?php echo $this->get_field_name('display_valuescolor'); ?>"
value="<?php echo esc_attr($display_valuescolor); ?>">
</p>
<p>
<label for="<?php echo $this->get_field_id('fontTypeCombo'); ?>"><?php _e('Font Type:'); ?></label>
<select class="widefat" id="<?php echo $this->get_field_id('fontTypeCombo'); ?>"
name="<?php echo $this->get_field_name('fontTypeCombo'); ?>">
<optgroup class='verdana'>
<option <?php selected($fontTypeCombo, 'font-family:Verdana, Geneva, sans-serif'); ?>
value="font-family:Verdana, Geneva, sans-serif">Verdana</option>
</optgroup>
<optgroup class='TimesNew'>
<option <?php selected($fontTypeCombo, "font-family:'Times New Roman', Times, serif"); ?>
value="font-family:'Times New Roman', Times, serif">Times New Roman</option>
</optgroup>
<optgroup class='Arial'>
<option <?php selected($fontTypeCombo, "font-family:Arial, Helvetica, sans-serif"); ?>
value="font-family:Arial, Helvetica, sans-serif">Arial</option>
</optgroup>
<optgroup class='Tahoma'>
<option <?php selected($fontTypeCombo, "font-family:Tahoma, Geneva, sans-serif"); ?>
value="font-family:Tahoma, Geneva, sans-serif">Tahoma</option>
</optgroup>
<optgroup class='Courier'>
<option <?php selected($fontTypeCombo, "font-family:'Courier New', Courier, monospace"); ?>
value="font-family:'Courier New', Courier, monospace">Courier</option>
</optgroup>
<optgroup class='TrebuchetMS'>
<option <?php selected($fontTypeCombo, "font-family:'Trebuchet MS', Arial, Helvetica, sans-serif"); ?>
value="font-family:'Trebuchet MS', Arial, Helvetica, sans-serif">Trebuchet MS</option>
</optgroup>
</select>
</p>
<label for="<?php echo $this->get_field_id('fontSizeCombo'); ?>"><?php _e('Font Size:'); ?></label>
<select class="widefat" id="<?php echo $this->get_field_id('fontSizeCombo'); ?>"
name="<?php echo $this->get_field_name('fontSizeCombo'); ?>">
<?php
for ($fs = 8; $fs <= 22; $fs++) {
?>
<option value="<?php echo $fs ?>" <?php selected($fontSizeCombo, $fs); ?>><?php echo $fs; ?>px</option>
<?php } ?>
</select>
<p>
</p>
<p><em>Display :</em></p>
<?php
$display_onlineusers = isset($display_onlineusers) ? $display_onlineusers : '0';
$display_visitorstoday = isset($display_visitorstoday) ? $display_visitorstoday : '0';
$display_pageviewtoday = isset($display_pageviewtoday) ? $display_pageviewtoday : '0';
$display_totalpageview = isset($display_totalpageview) ? $display_totalpageview : '0';
$display_totalvisitors = isset($display_totalvisitors) ? $display_totalvisitors : '0';
?>
<p>
<input class="widefat" id="<?php echo $this->get_field_id('display_onlineusers'); ?>"
name="<?php echo $this->get_field_name('display_onlineusers'); ?>" type="checkbox" value="1"
<?php checked($display_onlineusers, '1'); ?> /> <label
for="<?php echo $this->get_field_id('display_onlineusers'); ?>">Users Online</label>
</p>
<p>
<input class="widefat" id="<?php echo $this->get_field_id('display_visitorstoday'); ?>"
name="<?php echo $this->get_field_name('display_visitorstoday'); ?>" type="checkbox" value="1"
<?php checked($display_visitorstoday, '1'); ?> /> <label
for="<?php echo $this->get_field_id('display_visitorstoday'); ?>">Visitors Today</label>
</p>
<p>
<input class="widefat" id="<?php echo $this->get_field_id('display_pageviewtoday'); ?>"
name="<?php echo $this->get_field_name('display_pageviewtoday'); ?>" type="checkbox" value="1"
<?php checked($display_pageviewtoday, '1'); ?> /> <label
for="<?php echo $this->get_field_id('display_pageviewtoday'); ?>">Page Views Today</label>
</p>
<p>
<input class="widefat" id="<?php echo $this->get_field_id('display_totalpageview'); ?>"
name="<?php echo $this->get_field_name('display_totalpageview'); ?>" type="checkbox" value="1"
<?php checked($display_totalpageview, '1'); ?> /> <label
for="<?php echo $this->get_field_id('display_totalpageview'); ?>">Total Page Views</label>
</p>
<p>
<input class="widefat" id="<?php echo $this->get_field_id('display_totalvisitors'); ?>"
name="<?php echo $this->get_field_name('display_totalvisitors'); ?>" type="checkbox" value="1"
<?php checked($display_totalvisitors, '1'); ?> /> <label
for="<?php echo $this->get_field_id('display_totalvisitors'); ?>">Total Visitors</label>
</p>
</p>
<?php
}
// Updating widget replacing old instances with new
public function update($new_instance, $old_instance)
{
return $new_instance;
}
}
// Class vtrts_widget ends here
// Register and load the widget
function ahcpro_wpb_load_widget()
{
register_widget('vtrts_widget');
}
add_action('widgets_init', 'ahcpro_wpb_load_widget');
function ahcpro_get_hits_by_custom_duration_callback()
{
$hits_duration = $_POST['hits_duration'];
$custom_timezone_offset = ahcpro_get_current_timezone_offset();
$custom_timezone = new DateTimeZone(ahcpro_get_timezone_string());
$myend_date = new DateTime();
$myend_date->setTimezone($custom_timezone);
$end_date = $myend_date->format('Y-m-d');
$full_end_date = $myend_date->format('Y-m-d 23:59:59');
$mystart_date = new DateTime();
$mystart_date->setTimezone($custom_timezone);
$stat = '';
switch ($hits_duration) {
case '7':
$mystart_date->modify('-6 days');
$start_date = $mystart_date->format('Y-m-d');
$full_start_date = $mystart_date->format('Y-m-d 00:00:00');
$interval = '1 day';
break;
case 'current_month':
//$mystart_date->modify('0:00 first day of curent month');
$start_date = $mystart_date->format('Y-m-01');
$end_date = $mystart_date->format('Y-m-t');
$full_start_date = $mystart_date->format('Y-m-01');
$full_end_date = $mystart_date->format('Y-m-t');
$interval = '1 day';
$stat = 'current_month';
break;
case 'last_month':
$mystart_date->modify('0:00 first day of previous month');
$start_date = $mystart_date->format('Y-m-d');
$end_date = $mystart_date->format('Y-m-t');
$full_start_date = $mystart_date->format('Y-m-d');
$full_end_date = $mystart_date->format('Y-m-t');
$interval = '1 day';
$stat = 'last_month';
break;
case '30':
/*$mystart_date->modify('first day of previous month');
$start_date = $mystart_date->format('Y-m-d');
$full_start_date = $mystart_date->format('Y-m-d H:i:s');
$myend_date->modify('last day of previous month');
$end_date = $myend_date->format('Y-m-d');
$full_end_date = $myend_date->format('Y-m-d H:i:s');*/
$mystart_date->modify('-30 days');
$start_date = $mystart_date->format('Y-m-d');
$full_start_date = $mystart_date->format('Y-m-d 00:00:00');
$interval = '1 week';
break;
case '0':
$mystart_date->modify('+1 month');
$full_end_date = $mystart_date->format('Y-m-1 23:59:00');
$mystart_date->modify('-1 years');
$start_date = $mystart_date->format('Y-m-1');
$full_start_date = $mystart_date->format('Y-m-1 00:00:00');
$stat = 'year';
$interval = '1 month';
break;
case 'range':
$full_start_date = $start_date = $_POST['hits_duration_from'];
$full_end_date = $_POST['hits_duration_to'];
$interval = '1 day';
break;
default:
$mystart_date->modify(' - ' . (AHCPRO_VISITORS_VISITS_LIMIT - 1) . ' days');
$start_date = $mystart_date->format('Y-m-d');
$full_start_date = $mystart_date->format('Y-m-d 00:00:00');
$interval = '1 day';
break;
}
$visits_visitors_data = ahcpro_get_visits_by_custom_duration_callback($full_start_date, $full_end_date, $stat);
//print_r($visits_visitors_data);
$response = array(
'mystart_date' => $start_date,
'myend_date' => $end_date,
'full_start_date' => $full_start_date,
'full_end_date' => $full_end_date,
'interval' => $interval,
'visitors_data' => json_encode($visits_visitors_data['visitors']),
'visits_data' => json_encode($visits_visitors_data['visits'])
);
echo json_encode($response);
die;
}
function ahcpro_get_visits_by_custom_duration_callback($start_date, $end_date, $stat)
{
global $wpdb;
$visits_arr = array();
$custom_timezone_offset = ahcpro_get_current_timezone_offset();
$custom_timezone = new DateTimeZone(ahcpro_get_timezone_string());
$results = false;
$mystart_date = new DateTime($start_date);
$myend_date = new DateTime($end_date);
$total_days = date_diff($mystart_date, $myend_date);
$total_days = $total_days->format("%a");
$cond = "DATE(CONVERT_TZ(vst_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) >= DATE('" . $start_date . " 00:00:00') AND DATE(CONVERT_TZ(vst_date, '" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "')) <= DATE('" . $end_date . " 23:59:59')";
if ($stat == 'year') {
$sql = "SELECT DATE_FORMAT(CONVERT_TZ(vst_date,'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "'),'%Y-%m') as group_date,DATE_FORMAT(CONVERT_TZ(vst_date,'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "'),'%Y-%m-01') as vst_date,SUM(vst_visitors) as vst_visitors,SUM(vst_visits) as vst_visits FROM ahc_visitors WHERE ahc_visitors.site_id = " . get_current_blog_id() . " and " . $cond . " GROUP BY group_date";
}
if ($stat == 'all') {
$sql = "SELECT DATE_FORMAT(CONVERT_TZ(vst_date,'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "', '" . $custom_timezone_offset . "'),'%Y-%m') as group_date,DATE_FORMAT(CONVERT_TZ(vst_date,'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "'),'%Y-%m-01') as vst_date,SUM(vst_visitors) as vst_visitors,SUM(vst_visits) as vst_visits FROM ahc_visitors where ahc_visitors.site_id = " . get_current_blog_id() . " GROUP BY group_date ORDER BY vst_date ASC";
}
if ($stat == '' || $stat == 'current_month' || $stat == 'last_month') {
$sql = "SELECT DATE(CONVERT_TZ(vst_date,'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "')) as vst_date, SUM(vst_visits) AS vst_visits,SUM(vst_visitors) as vst_visitors FROM ahc_visitors WHERE ahc_visitors.site_id = " . get_current_blog_id() . " and " . $cond . " GROUP BY DATE(CONVERT_TZ(vst_date,'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "'))";
}
//echo $sql;
$results = $wpdb->get_results($sql, OBJECT);
if ($results !== false) {
//print_r(ahcpro_localtime('n'));
if ($stat == 'year') {
for ($i = 1; $i <= 12; $i++) {
$month = $mystart_date->format('m');
$year = $mystart_date->format('Y');
$total_days = cal_days_in_month(CAL_GREGORIAN, $month, $year);
$visits_arr['visits'][] = array($mystart_date->format('Y-m-d'), 0);
$visits_arr['visitors'][] = array($mystart_date->format('Y-m-d'), 0);
$mystart_date->modify('+' . $total_days . ' days');
}
} elseif ($stat == 'all') {
foreach ($results as $key => $element) {
reset($results);
if ($key === key($results)) {
$first_date = $element->vst_date;
}
end($results);
if ($key === key($results)) {
$last_date = $element->vst_date;
}
}
$d1 = new DateTime($first_date);
$d2 = new DateTime($last_date);
if (count($results) == 1) {
$pre_d1 = new DateTime($first_date);
$pre_d1->modify('first day of previous month');
$visits_arr['visits'][] = array($pre_d1->format('Y-m-d'), 0);
$visits_arr['visitors'][] = array($pre_d1->format('Y-m-d'), 0);
}
$diff = $d1->diff($d2)->m + 1;
for ($i = 1; $i <= $diff; $i++) {
$visits_arr['visits'][] = array($d1->format('Y-m-d'), 0);
$visits_arr['visitors'][] = array($d1->format('Y-m-d'), 0);
$d1->modify('+1 Month');
}
} else {
if ($stat == 'current_month') {
$total_days = ahcpro_localtime('t');
$total_days--;
}
if ($stat == 'last_month') {
$total_days = ahcpro_localtime('t', strtotime('first day of previous month'));
$total_days--;
}
$visits_arr['visits'][] = array($mystart_date->format('Y-m-d'), 0);
$visits_arr['visitors'][] = array($mystart_date->format('Y-m-d'), 0);
for ($i = 1; $i <= $total_days; $i++) {
$mystart_date->modify('+1 Day');
$visits_arr['visits'][] = array($mystart_date->format('Y-m-d'), 0);
$visits_arr['visitors'][] = array($mystart_date->format('Y-m-d'), 0);
}
}
//print_r($visits_arr);
foreach ($visits_arr['visits'] as $key => $visits) {
foreach ($results as $r) {
if ($visits[0] == $r->vst_date) {
$visits_arr['visits'][$key][1] = $r->vst_visits;
}
}
}
//echo' ||||||||| ';
//print_r($visits_arr['visits']);
foreach ($visits_arr['visitors'] as $key => $visits) {
foreach ($results as $r) {
if ($visits[0] == $r->vst_date) {
$visits_arr['visitors'][$key][1] = $r->vst_visitors;
}
}
}
}
//echo $wpdb->last_query;
return $visits_arr;
}
function admin_notice_to_set_timezone()
{
$class = 'notice notice-error';
$name = 'Visitor Traffic Real Time Statistics Pro - Invalid Timezone';
$message = sprintf(__('Invalid timezone, Please visit the <a href="%s">settings</a> page and select your current timezone.'), site_url('wp-admin/admin.php?page=ahc_hits_counter_settings'));
printf('<br><div class="%1$s" style="padding-top:5px;"><b>%2$s</b><p>%3$s</p></div>', esc_attr($class), $name, $message);
}
/*function ahcpro_get_visitors_by_custom_duration_callback( $start_date,$end_date ){
global $wpdb;
$visitors_arr = array();
$custom_timezone_offset = ahcpro_get_current_timezone_offset();
$custom_timezone = new DateTimeZone(ahcpro_get_timezone_string());
$results = false;
$mystart_date = new DateTime($start_date);
$myend_date = new DateTime($end_date);
$total_days = date_diff( $mystart_date, $myend_date );
$total_days = $total_days->format("%a");
if($start_date == 'all'){
$cond = "DATE(CONVERT_TZ(vst_date, " . AHCPRO_SERVER_CURRENT_TIMEZONE . ", '" . $custom_timezone_offset . "')) <= DATE('". $end_date ."')";
}
else{
$cond = "DATE(CONVERT_TZ(vst_date, " . AHCPRO_SERVER_CURRENT_TIMEZONE . ", '" . $custom_timezone_offset . "')) <= DATE('". $end_date ."') AND DATE(CONVERT_TZ(vst_date, " . AHCPRO_SERVER_CURRENT_TIMEZONE . ", '" . $custom_timezone_offset . "')) >= DATE('". $start_date ."')";
}
$sql = "SELECT DATE(CONVERT_TZ(vst_date," . AHCPRO_SERVER_CURRENT_TIMEZONE . ",'" . $custom_timezone_offset . "')) as vst_date, vst_visitors
FROM ahc_visitors
WHERE ". $cond;
$results = $wpdb->get_results($sql, OBJECT);
if ($results !== false) {
$mystart_date->modify( '-1 Day' );
for ($i = count($results); $i < $total_days; $i++) {
$visitors_arr[] = array($mystart_date->format('Y-m-d') , 0 );
$mystart_date->modify( '+1 Day' );
}
foreach ($results as $r) {
$hitDate = new DateTime($r->vst_date);
$visitors_arr[] = array($hitDate->format('Y-m-d'), $r->vst_visitors);
}
}
return $visitors_arr;
}*/
function getFormattedDate($date, $format = "")
{
if ($date != '') {
if ($format == "yymmdd")
return DateTime::createFromFormat('m-d-Y', $date)->format('Y-m-d');
else
return DateTime::createFromFormat('m-d-Y', $date)->format('m/d/Y');
}
}
add_action("wp_ajax_traffic_by_countries", "traffic_by_countries_callback");
function traffic_by_countries_callback()
{
if (isset($_REQUEST['page']) && $_REQUEST['page'] == "all") {
$res = ahcpro_get_top_countries(0, "", "", 1, false);
echo json_encode($res);
exit;
} else {
$tTitles = ahcpro_get_top_countries(0, $_REQUEST['start'], $_REQUEST['length'], "", false);
$cnt = ahcpro_get_top_countries(0, "", "", "", true);
$arr["draw"] = 0;
$arr["recordsTotal"] = $cnt;
$arr["recordsFiltered"] = $cnt;
$arr['data'] = $tTitles['data'];
echo json_encode($arr);
exit;
}
}
// add_action("wp_ajax_recent_visitor_by_ip", "recent_visitor_by_ip_callback");
// function recent_visitor_by_ip_callback()
// {
// $all = (isset($_REQUEST['page']) && $_REQUEST['page'] > 0) ? 1 : 0;
// $cnt = ahcpro_get_recent_visitors($all, true, "", "", $_REQUEST['year'], $_REQUEST['month'], $_REQUEST['ip']);
// $recentVisitors = ahcpro_get_recent_visitors($all, false, $_REQUEST['start'], $_REQUEST['length'], $_REQUEST['year'], $_REQUEST['month'], $_REQUEST['ip']);
// $arr["draw"] = 0;
// $arr["recordsTotal"] = $cnt;
// $arr["recordsFiltered"] = $cnt;
// $arr['data'] = $recentVisitors;
// echo json_encode($arr);
// exit;
// }
add_action("wp_ajax_latest_search_words", "latest_search_words_callback");
function latest_search_words_callback()
{
// First, test the GSC connection
$gsc = new GoogleSearchConsoleIntegration();
$connection_test = $gsc->test_connection();
// If connection fails or site not found, return error
if (!$connection_test['success'] || empty($connection_test['current_site_found'])) {
$error_response = [
'success' => false,
'error' => false,
'message' => 'Search Console data not available. Please check your API connection settings.',
'detailed_message' => $connection_test['message'] ?? 'Connection test failed'
];
wp_send_json($error_response);
return;
}
// Connection is good, proceed with normal data retrieval
try {
if (isset($_REQUEST['page']) && $_REQUEST['page'] == "all") {
$res = ahcpro_get_latest_search_key_words_used(1, false, "", "", $_REQUEST['fdt'], $_REQUEST['tdt']);
// Check if we got data
if (empty($res) || $res === false) {
wp_send_json([
'success' => false,
'error' => false,
'message' => 'No search data available yet. This is normal for new sites - Google needs 1-3 days to collect search data.',
'data' => []
]);
return;
}
wp_send_json([
'success' => true,
'data' => $res
]);
} else {
// DataTables format response
$cnt = ahcpro_get_latest_search_key_words_used("", true, "", "", $_REQUEST['fdt'], $_REQUEST['tdt']);
$recentVisitors = ahcpro_get_latest_search_key_words_used("", false, $_REQUEST['start'], $_REQUEST['length'], $_REQUEST['fdt'], $_REQUEST['tdt']);
// Check if we got data
if (empty($recentVisitors) || $recentVisitors === false) {
wp_send_json([
'success' => false,
'error' => false,
'message' => 'No search data available yet. This is normal for new sites - Google needs 1-3 days to collect search data.',
'draw' => intval($_REQUEST['draw'] ?? 0),
'recordsTotal' => 0,
'recordsFiltered' => 0,
'data' => []
]);
return;
}
$arr = [
'success' => true,
'draw' => intval($_REQUEST['draw'] ?? 0),
'recordsTotal' => $cnt,
'recordsFiltered' => $cnt,
'data' => $recentVisitors
];
wp_send_json($arr);
}
} catch (Exception $e) {
wp_send_json([
'success' => false,
'error' => true,
'message' => 'Error retrieving search data: ' . $e->getMessage()
]);
}
}
add_action("wp_ajax_today_traffic_index", "today_traffic_index_callback");
function today_traffic_index_callback()
{
if (isset($_REQUEST['page']) && $_REQUEST['page'] == "all") {
$res = ahcpro_get_vsitors_by_country(1, false, "", "", $_REQUEST['fdt'], $_REQUEST['tdt']);
echo json_encode($res);
exit;
} else {
$cnt = ahcpro_get_vsitors_by_country("", true, "", "", $_REQUEST['fdt'], $_REQUEST['tdt']);
$countries = ahcpro_get_vsitors_by_country("", false, $_REQUEST['start'], $_REQUEST['length'], $_REQUEST['fdt'], $_REQUEST['tdt']);
$arr["draw"] = 0;
$arr["recordsTotal"] = $cnt;
$arr["recordsFiltered"] = $cnt;
$arr['data'] = $countries;
echo json_encode($arr);
exit;
}
}
add_action("wp_ajax_visits_time_graph", "visits_time_graph_callback");
function visits_time_graph_callback()
{
if (isset($_REQUEST['page']) && $_REQUEST['page'] == "all") {
$times = ahcpro_get_time_visits(1, "", "", $_REQUEST['fdt'], $_REQUEST['tdt']);
echo json_encode($times);
exit;
} else {
$times = ahcpro_get_time_visits("", $_REQUEST['start'], $_REQUEST['length'], $_REQUEST['fdt'], $_REQUEST['tdt']);
//$res = ahcpro_get_time_visits("","","",$_REQUEST['fdt'],$_REQUEST['tdt']);
$cnt = 24;
$arr["draw"] = 0;
$arr["recordsTotal"] = $cnt;
$arr["recordsFiltered"] = $cnt;
$arr['data'] = $times;
echo json_encode($arr);
exit;
}
}
add_action("wp_ajax_ip_history", "ip_history_callback");
function ip_history_callback()
{
global $wpdb;
$wp_timezone_string = get_option('timezone_string');
$custom_timezone_offset = (get_option('ahcpro_custom_timezone') != '') ? get_option('ahcpro_custom_timezone') : $wp_timezone_string;
$sql_query = "SELECT *, DATE_FORMAT(CONVERT_TZ(CONCAT_WS(' ',hit_date, hit_time),'" . AHCPRO_SERVER_CURRENT_TIMEZONE . "','" . $custom_timezone_offset . "'), '%H:%i:%s') as hit_time FROM `ahc_hits` where site_id = " . get_current_blog_id() . " and `hit_ip_address` = '" . $_POST['hitipaddress'] . "' and `hit_date` = '" . $_POST['hitdate'] . "' and `hit_page_title` !='' order by `hit_id` asc limit 30 ";
$results = $wpdb->get_results($sql_query);
if ($results !== false) {
if (is_array($results)) {
$ret = '<h4>IP: ' . ahcfpro_haship($_POST['hitipaddress']) . ' - ' . $_POST['hitcountry'] . $custom_timezone_offset . '</h4><table class="table table-striped">
<thead>
<tr>
<th scope="col">Page Title</th>
<th scope="col">Time</th>
</tr>
</thead>
<tbody>';
$cnt = 1;
foreach ($results as $hit) {
$ret .= '<tr>
<td scope="row" width="70%"><a target="_blank" href="' . home_url($hit->hit_request_uri) . '">' . $cnt . '- ' . $hit->hit_page_title . '</a>
<br><a target="_blank" href="' . home_url($hit->hit_request_uri) . '"><small style="color:gray">' . home_url($hit->hit_request_uri) . '</small></a>
</td>
<td>' . $hit->hit_date . ' <small style="color:gray">' . $hit->hit_time . '<small></td>
</tr>';
$cnt++;
}
$ret .= '</tbody>
</table>';
echo $ret;
exit();
}
}
}
/**
* Get the count of new visitors (total only - optimized)
* OPTIMIZED: Uses fastest possible query like free version
*
* @param string $period Optional. Only 'total' supported for performance
* @return int Number of new visitors
*/
function ahcpro_get_new_visitors($period = 'total')
{
global $wpdb;
// Performance: Only support total for maximum speed
$sql = "SELECT COUNT(DISTINCT vtr_ip_address) as new_visitors
FROM ahc_recent_visitors
WHERE site_id = " . get_current_blog_id();
$result = $wpdb->get_var($sql);
return $result ? (int)$result : 0;
}
/**
* Get the count of returning visitors (total only - optimized)
* OPTIMIZED: Uses simple GROUP BY logic from free version
*
* @param string $period Optional. Only 'total' supported for performance
* @return int Number of returning visitors
*/
function ahcpro_get_returning_visitors($period = 'total')
{
global $wpdb;
// Performance: Count IPs that visited on multiple different dates (fastest approach)
$sql = "SELECT COUNT(*) as returning_visitors
FROM (
SELECT vtr_ip_address
FROM ahc_recent_visitors
WHERE site_id = " . get_current_blog_id() . "
GROUP BY vtr_ip_address
HAVING COUNT(DISTINCT DATE(vtr_date)) > 1
) as returning_ips";
$result = $wpdb->get_var($sql);
return $result ? (int)$result : 0;
}
/**
* Get the bounce rate (total only - optimized)
* OPTIMIZED: Uses session counting approach from free version
*
* @param string $period Optional. Only 'total' supported for performance
* @return float Bounce rate percentage
*/
function ahcpro_get_bounce_rate($period = 'total')
{
global $wpdb;
// Performance: Count sessions with only one page view (all-time)
$single_page_sessions = $wpdb->get_var(
"SELECT COUNT(*) as single_sessions
FROM (
SELECT CONCAT(hit_ip_address, '-', DATE(hit_date)) as session_id
FROM ahc_hits
WHERE site_id = " . get_current_blog_id() . "
GROUP BY session_id
HAVING COUNT(DISTINCT hit_page_id) = 1
) as single_session_data"
);
// Get total sessions (all-time)
$total_sessions = $wpdb->get_var(
"SELECT COUNT(DISTINCT CONCAT(hit_ip_address, '-', DATE(hit_date))) as total_sessions
FROM ahc_hits
WHERE site_id = " . get_current_blog_id()
);
if ($total_sessions > 0) {
return round(($single_page_sessions / $total_sessions) * 100, 1);
}
return 0;
}
/**
* Get the average session duration (total only - optimized)
* OPTIMIZED: Uses simplified calculation from free version
*
* @param string $period Optional. Only 'total' supported for performance
* @return string Formatted average session duration (e.g., "2m 15s")
*/
function ahcpro_get_average_session_duration($period = 'total')
{
global $wpdb;
// Performance: Calculate average time between first and last hit per session (all-time)
$avg_duration = $wpdb->get_var(
"SELECT AVG(session_duration) as avg_duration
FROM (
SELECT
CONCAT(hit_ip_address, '-', DATE(hit_date)) as session_id,
TIMESTAMPDIFF(SECOND,
MIN(CONCAT(hit_date, ' ', hit_time)),
MAX(CONCAT(hit_date, ' ', hit_time))
) as session_duration
FROM ahc_hits
WHERE site_id = " . get_current_blog_id() . "
GROUP BY session_id
HAVING COUNT(*) > 1
) as sessions"
);
if ($avg_duration && $avg_duration > 0) {
return ahcpro_format_duration(round($avg_duration));
}
return "0m 0s";
}
/**
* Helper function to format session duration
* Same as free version for consistency
*/
function ahcpro_format_duration($seconds)
{
if ($seconds < 60) {
return $seconds . 's';
} elseif ($seconds < 3600) {
$minutes = floor($seconds / 60);
$remaining_seconds = $seconds % 60;
return $minutes . 'm ' . $remaining_seconds . 's';
} else {
$hours = floor($seconds / 3600);
$minutes = floor(($seconds % 3600) / 60);
return $hours . 'h ' . $minutes . 'm';
}
}
/**
*/
function ahcpro_get_summary_statistics()
{
$arr = array();
// Get standard period-based stats (unchanged)
$arr['today'] = ahcpro_get_visitors_visits_in_period('today');
$arr['yesterday'] = ahcpro_get_visitors_visits_in_period('yesterday');
$arr['week'] = ahcpro_get_visitors_visits_in_period('week'); // last 7 days
$arr['month'] = ahcpro_get_visitors_visits_in_period('month');
$arr['year'] = ahcpro_get_visitors_visits_in_period('year');
$arr['total'] = ahcpro_get_visitors_visits_in_period();
// Add optimized total-only new visitor metrics (maximum speed)
$arr['new_visitors'] = ahcpro_get_new_visitors('total');
$arr['returning_visitors'] = ahcpro_get_returning_visitors('total');
$arr['bounce_rate'] = ahcpro_get_bounce_rate('total');
$arr['avg_session_duration'] = ahcpro_get_average_session_duration('total');
return $arr;
}
/**
* Get last 7 days breakdown for sparkline charts in dashboard boxes
* Returns visitors and visits per day for the last 7 days (oldest to newest)
*
* @return array [['date'=>'YYYY-MM-DD','visitors'=>int,'visits'=>int], ...]
*/
function ahcpro_get_last_7_days_data()
{
global $wpdb;
$custom_timezone_offset = ahcpro_get_current_timezone_offset();
$custom_timezone = new DateTimeZone(ahcpro_get_timezone_string());
$site_id = get_current_blog_id();
// ابني مصفوفة لآخر 7 أيام (من القديم إلى الأحدث)
$days = array();
for ($i = 6; $i >= 0; $i--) {
$d = new DateTime('now', $custom_timezone);
$d->modify('-' . $i . ' day');
$days[$d->format('Y-m-d')] = array(
'date' => $d->format('Y-m-d'),
'visitors' => 0,
'visits' => 0,
);
}
$start_date = array_keys($days)[0];
$end_date = array_keys($days)[6];
$sql = $wpdb->prepare(
"SELECT DATE(CONVERT_TZ(vst_date, %s, %s)) AS dt,
SUM(vst_visitors) AS visitors,
SUM(vst_visits) AS visits
FROM `ahc_visitors`
WHERE site_id = %d
AND DATE(CONVERT_TZ(vst_date, %s, %s)) >= %s
AND DATE(CONVERT_TZ(vst_date, %s, %s)) <= %s
GROUP BY DATE(CONVERT_TZ(vst_date, %s, %s))",
AHCPRO_SERVER_CURRENT_TIMEZONE, $custom_timezone_offset,
$site_id,
AHCPRO_SERVER_CURRENT_TIMEZONE, $custom_timezone_offset, $start_date,
AHCPRO_SERVER_CURRENT_TIMEZONE, $custom_timezone_offset, $end_date,
AHCPRO_SERVER_CURRENT_TIMEZONE, $custom_timezone_offset
);
$results = $wpdb->get_results($sql, OBJECT);
if (is_array($results)) {
foreach ($results as $row) {
if (isset($days[$row->dt])) {
$days[$row->dt]['visitors'] = (int) $row->visitors;
$days[$row->dt]['visits'] = (int) $row->visits;
}
}
}
return array_values($days);
}
/**
* ULTRA-FAST VERSION: Get all enhanced stats in one call
* Performance: Single database connection, optimized queries
*/
function ahcpro_get_enhanced_total_statistics()
{
global $wpdb;
$site_id = get_current_blog_id();
// Performance: Get all metrics in minimal queries
$stats = array();
// 1. Get new visitors (unique IPs) - fastest possible
$stats['new_visitors'] = (int)$wpdb->get_var(
"SELECT COUNT(DISTINCT vtr_ip_address)
FROM ahc_recent_visitors
WHERE site_id = {$site_id}"
);
// 2. Get returning visitors - optimized grouping
$stats['returning_visitors'] = (int)$wpdb->get_var(
"SELECT COUNT(*)
FROM (
SELECT vtr_ip_address
FROM ahc_recent_visitors
WHERE site_id = {$site_id}
GROUP BY vtr_ip_address
HAVING COUNT(DISTINCT DATE(vtr_date)) > 1
) as returning_ips"
);
// 3. Get bounce rate data in one query
$bounce_data = $wpdb->get_row(
"SELECT
COUNT(*) as total_sessions,
SUM(CASE WHEN page_count = 1 THEN 1 ELSE 0 END) as single_page_sessions
FROM (
SELECT
CONCAT(hit_ip_address, '-', DATE(hit_date)) as session_id,
COUNT(DISTINCT hit_page_id) as page_count
FROM ahc_hits
WHERE site_id = {$site_id}
GROUP BY session_id
) as session_data"
);
if ($bounce_data && $bounce_data->total_sessions > 0) {
$stats['bounce_rate'] = round(($bounce_data->single_page_sessions / $bounce_data->total_sessions) * 100, 1);
} else {
$stats['bounce_rate'] = 0;
}
// 4. Get average session duration - optimized
$avg_duration = $wpdb->get_var(
"SELECT AVG(session_duration)
FROM (
SELECT
TIMESTAMPDIFF(SECOND,
MIN(CONCAT(hit_date, ' ', hit_time)),
MAX(CONCAT(hit_date, ' ', hit_time))
) as session_duration
FROM ahc_hits
WHERE site_id = {$site_id}
GROUP BY CONCAT(hit_ip_address, '-', DATE(hit_date))
HAVING COUNT(*) > 1
) as sessions"
);
$stats['avg_session_duration'] = ($avg_duration && $avg_duration > 0) ?
ahcpro_format_duration(round($avg_duration)) : "0m 0s";
return $stats;
}
/**
* PERFORMANCE OPTIMIZED: Complete summary with enhanced stats
* Combines standard stats with ultra-fast enhanced metrics
*/
function ahcpro_get_complete_summary_statistics()
{
// Get standard period stats
$arr = array();
$arr['today'] = ahcpro_get_visitors_visits_in_period('today');
$arr['yesterday'] = ahcpro_get_visitors_visits_in_period('yesterday');
$arr['week'] = ahcpro_get_visitors_visits_in_period('week');
$arr['month'] = ahcpro_get_visitors_visits_in_period('month');
$arr['year'] = ahcpro_get_visitors_visits_in_period('year');
$arr['total'] = ahcpro_get_visitors_visits_in_period();
// Get enhanced stats in one ultra-fast call
$enhanced_stats = ahcpro_get_enhanced_total_statistics();
// Merge enhanced stats into result
$arr['new_visitors'] = $enhanced_stats['new_visitors'];
$arr['returning_visitors'] = $enhanced_stats['returning_visitors'];
$arr['bounce_rate'] = $enhanced_stats['bounce_rate'];
$arr['avg_session_duration'] = $enhanced_stats['avg_session_duration'];
return $arr;
}
add_action('wp_ajax_ahcpro_get_visitor_path', 'ahcpro_get_visitor_path_callback');
function ahcpro_get_visitor_path_callback()
{
global $wpdb;
$ip = isset($_POST['hitipaddress']) ? $_POST['hitipaddress'] : '';
$date = isset($_POST['hitdate']) ? $_POST['hitdate'] : '';
$site_id = get_current_blog_id();
$pages = [];
$user_agent = '';
$browser = '';
$os = '';
// Get visited pages for this session
$results = $wpdb->get_results($wpdb->prepare(
"SELECT hit_time, hit_page_title, hit_request_uri, hit_referer, hit_user_agent FROM ahc_hits WHERE site_id = %d AND hit_ip_address = %s AND hit_date = %s AND hit_page_title != '' ORDER BY hit_id ASC LIMIT 30",
$site_id,
$ip,
$date
));
if ($results) {
foreach ($results as $hit) {
$pages[] = [
'time' => $hit->hit_time,
'title' => $hit->hit_page_title,
'url' => home_url($hit->hit_request_uri),
'referrer' => $hit->hit_referer
];
$user_agent = $hit->hit_user_agent; // last one will be the latest
}
}
// Parse user agent for browser and OS
if ($user_agent) {
list($browser, $os) = ahcpro_parse_user_agent($user_agent);
}
wp_send_json([
'pages' => $pages,
'browser' => $browser,
'os' => $os
]);
}
function ahcpro_parse_user_agent($ua)
{
$browser = 'Unknown';
$os = 'Unknown';
// OS
if (preg_match('/Windows NT 10.0/i', $ua)) $os = 'Windows 10/11';
elseif (preg_match('/Windows NT 6.3/i', $ua)) $os = 'Windows 8.1';
elseif (preg_match('/Windows NT 6.2/i', $ua)) $os = 'Windows 8';
elseif (preg_match('/Windows NT 6.1/i', $ua)) $os = 'Windows 7';
elseif (preg_match('/Mac OS X ([\d_]+)/i', $ua, $m)) $os = 'macOS ' . str_replace('_', '.', $m[1]);
elseif (preg_match('/Android ([\d.]+)/i', $ua, $m)) $os = 'Android ' . $m[1];
elseif (preg_match('/iPhone OS ([\d_]+)/i', $ua, $m)) $os = 'iOS ' . str_replace('_', '.', $m[1]);
elseif (preg_match('/Linux/i', $ua)) $os = 'Linux';
// Browser
if (preg_match('/Edg\/([\d.]+)/i', $ua, $m)) $browser = 'Edge ' . $m[1];
elseif (preg_match('/OPR\/([\d.]+)/i', $ua, $m)) $browser = 'Opera ' . $m[1];
elseif (preg_match('/Chrome\/([\d.]+)/i', $ua, $m)) $browser = 'Chrome ' . $m[1];
elseif (preg_match('/Firefox\/([\d.]+)/i', $ua, $m)) $browser = 'Firefox ' . $m[1];
elseif (preg_match('/Safari\/([\d.]+)/i', $ua, $m) && !preg_match('/Chrome/i', $ua)) $browser = 'Safari ' . $m[1];
return [$browser, $os];
}
function ahcpro_get_latest_search_keywords_with_gsc($limit = 50, $from_date = '', $to_date = '')
{
global $wpdb;
// Build date condition if dates are provided
$date_condition = '';
if (!empty($from_date) && !empty($to_date)) {
$date_condition = $wpdb->prepare(
" AND k.kwd_date BETWEEN %s AND %s",
$from_date,
$to_date
);
}
// Get table names with proper prefix
$keywords_table = 'ahc_keywords';
$countries_table = 'ahc_countries';
$search_engines_table = 'ahc_search_engines';
$browsers_table = 'ahc_browsers';
$sql = "SELECT
k.kwd_keywords as hit_search_words,
k.kwd_referer as hit_referer,
k.kwd_date as hit_date,
k.kwd_time,
k.kwd_ip_address,
COALESCE(c.ctr_name, 'Unknown') as ctr_name,
COALESCE(c.ctr_internet_code, 'XX') as ctr_internet_code,
COALESCE(s.srh_name, 'Unknown') as srh_name,
COALESCE(s.srh_icon, 'unknown.png') as srh_icon,
COALESCE(b.bsr_name, 'Unknown') as bsr_name,
COALESCE(b.bsr_icon, 'unknown.png') as bsr_icon,
CONCAT(
COALESCE(c.ctr_name, 'Unknown'), '/',
COALESCE(s.srh_name, 'Unknown'), '/',
COALESCE(b.bsr_name, 'Unknown')
) as csb
FROM {$keywords_table} k
LEFT JOIN {$countries_table} c ON k.ctr_id = c.ctr_id
LEFT JOIN {$search_engines_table} s ON k.srh_id = s.srh_id
LEFT JOIN {$browsers_table} b ON k.bsr_id = b.bsr_id
WHERE k.site_id = %d
{$date_condition}
ORDER BY k.kwd_date DESC, k.kwd_time DESC
LIMIT %d";
try {
$results = $wpdb->get_results(
$wpdb->prepare($sql, get_current_blog_id(), $limit),
ARRAY_A
);
if ($wpdb->last_error) {
error_log('GSC Display Query Error: ' . $wpdb->last_error);
return array();
}
// Debug log to see what we're getting
error_log('GSC Display: Retrieved ' . count($results ? $results : []) . ' keyword records');
return $results ? $results : array();
} catch (Exception $e) {
error_log('GSC Display Exception: ' . $e->getMessage());
return array();
}
}
function ahc_enqueue_admin_bar_counter_script()
{
// Only load if user is logged in and admin bar is showing
if (is_user_logged_in() && is_admin_bar_showing()) {
wp_enqueue_script(
'ahc-admin-bar-counter',
plugins_url('/js/ahc_script.js', __FILE__), // Adjust path as needed
array('jquery'),
'1.0.0',
true
);
// Localize script for AJAX
wp_localize_script('ahc-admin-bar-counter', 'ahc_ajax', array(
'ajax_url' => admin_url('admin-ajax.php')
));
}
}
// Hook to enqueue on both frontend and backend
add_action('wp_enqueue_scripts', 'ahc_enqueue_admin_bar_counter_script');
add_action('admin_enqueue_scripts', 'ahc_enqueue_admin_bar_counter_script');
add_action('admin_enqueue_scripts', function () {
wp_localize_script('ahc_main_js', 'ahc_ajax', [
'ajax_url' => admin_url('admin-ajax.php'),
'test_gsc_nonce' => wp_create_nonce('test_gsc_nonce')
]);
});
// ============================================================
// WordPress Heartbeat API — استقبال ping من الزائر
// يُستدعى تلقائياً من WordPress كل 15-60 ثانية
// يحدّث عمود date في ahc_online_users الموجود أصلاً
// (لا يضيف أي عمود أو جدول جديد)
// ============================================================
add_filter('heartbeat_received', 'ahcpro_heartbeat_received', 10, 2);
add_filter('heartbeat_nopriv_received', 'ahcpro_heartbeat_received', 10, 2);
function ahcpro_heartbeat_received($response, $data)
{
if (empty($data['ahcpro_heartbeat_ip'])) {
return $response;
}
global $wpdb;
$ip = sanitize_text_field($data['ahcpro_heartbeat_ip']);
$site_id = get_current_blog_id();
// نستخدم نفس ahcpro_localtime التي يستخدمها INSERT الأصلي
// لضمان تطابق التوقيت في جميع السجلات
$now_local = ahcpro_localtime('Y-m-d H:i:s');
// نحدّث جميع سجلات الـ IP النشطة (ليس LIMIT 1)
// لضمان أن أي استعلام يقرأ أحدث وقت صحيح
$updated = $wpdb->query($wpdb->prepare(
"UPDATE `ahc_online_users`
SET `date` = %s
WHERE `hit_ip_address` = %s
AND `site_id` = %d
AND `date` >= DATE_SUB(%s, INTERVAL 2 HOUR)",
$now_local,
$ip,
$site_id,
$now_local
));
// Debug log — يمكن حذفه لاحقاً بعد التأكد
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log(sprintf(
'[ahcpro heartbeat] ip=%s site=%d rows_updated=%d last_error=%s',
$ip, $site_id, (int) $updated, $wpdb->last_error
));
}
// نضيف معلومات تشخيص في الـ response (يظهر في Network → Response)
$response['ahcpro_hb'] = array(
'ip' => $ip,
'rows_updated' => (int) $updated,
'error' => $wpdb->last_error,
);
return $response;
}
?>