= $max ) { continue; } } if ( ! $best || $rule['priority'] > $best['priority'] ) { $best = $rule; } } return $best; } /** * Cookie_Notice_Dashboard class. * * @class Cookie_Notice_Dashboard */ class Cookie_Notice_Dashboard { /** * Class constructor. * * @return void */ public function __construct() { // actions add_action( 'wp_dashboard_setup', [ $this, 'wp_dashboard_setup' ], 11 ); add_action( 'wp_network_dashboard_setup', [ $this, 'wp_dashboard_setup' ], 11 ); add_action( 'admin_enqueue_scripts', [ $this, 'admin_scripts_styles' ] ); // site status add_filter( 'site_status_tests', [ $this, 'add_tests' ] ); } /** * Initialize widget. * * @global array $wp_meta_boxes * * @return void */ public function wp_dashboard_setup() { // filter user_can_see_stats if ( ! current_user_can( apply_filters( 'cn_manage_cookie_notice_cap', 'manage_options' ) ) ) return; // get main instance $cn = Cookie_Notice(); // check when to hide widget if ( is_multisite() ) { // site dashboard if ( current_action() === 'wp_dashboard_setup' && $cn->is_plugin_network_active() && $cn->network_options['general']['global_override'] ) return; // network dashboard if ( current_action() === 'wp_network_dashboard_setup' ) { if ( $cn->is_plugin_network_active() ) { if ( ! $cn->network_options['general']['global_override'] ) return; } else return; } } // check is it network admin if ( $cn->is_network_admin() ) $dashboard_key = 'dashboard-network'; else $dashboard_key = 'dashboard'; global $wp_meta_boxes; // set widget key $widget_key = 'cn_dashboard_stats'; // add dashboard chart widget wp_add_dashboard_widget( $widget_key, __( 'Compliance by Hu-manity.co', 'cookie-notice' ), [ $this, 'dashboard_widget' ] ); // get widgets $normal_dashboard = $wp_meta_boxes[$dashboard_key]['normal']['core']; // attempt to place the widget at the top $widget_instance = [ $widget_key => $normal_dashboard[ $widget_key ] ]; // remove new widget unset( $normal_dashboard[ $widget_key ] ); // merge widgets $sorted_dashboard = array_merge( $widget_instance, $normal_dashboard ); // update widgets $wp_meta_boxes[$dashboard_key]['normal']['core'] = $sorted_dashboard; } /** * Enqueue admin scripts and styles. * * @param string $pagenow * @return void */ public function admin_scripts_styles( $pagenow ) { if ( $pagenow !== 'index.php' ) return; // filter user_can_see_stats if ( ! current_user_can( apply_filters( 'cn_manage_cookie_notice_cap', 'manage_options' ) ) ) return; // get main instance $cn = Cookie_Notice(); $date_format = get_option( 'date_format' ); if ( is_multisite() && $cn->is_network_admin() && $cn->is_plugin_network_active() && $cn->network_options['general']['global_override'] ) $analytics = get_site_option( 'cookie_notice_app_analytics', [] ); else $analytics = get_option( 'cookie_notice_app_analytics', [] ); // styles wp_enqueue_style( 'cookie-notice-admin-dashboard', COOKIE_NOTICE_URL . '/css/admin-dashboard.css', [], $cn->defaults['version'] ); wp_enqueue_style( 'cookie-notice-microtip', COOKIE_NOTICE_URL . '/assets/microtip/microtip.min.css', [], $cn->defaults['version'] ); // bail if compliance is not active if ( $cn->get_status() !== 'active' ) return; // scripts wp_register_script( 'cookie-notice-admin-chartjs', COOKIE_NOTICE_URL . '/assets/chartjs/chart.min.js', [ 'jquery' ], '4.5.1', true ); wp_enqueue_script( 'cookie-notice-admin-dashboard', COOKIE_NOTICE_URL . '/js/admin-dashboard.js', [ 'jquery', 'cookie-notice-admin-chartjs' ], $cn->defaults['version'], true ); // cycle usage data $cycle_usage = [ 'threshold' => ! empty( $analytics['cycleUsage']->threshold ) ? (int) $analytics['cycleUsage']->threshold : 0, 'visits' => ! empty( $analytics['cycleUsage']->visits ) ? (int) $analytics['cycleUsage']->visits : 0 ]; // no more than threshold available $cycle_usage['visits'] = $cycle_usage['visits'] > $cycle_usage['threshold'] ? $cycle_usage['threshold'] : $cycle_usage['visits']; // available visits, -1 for no pro plans $cycle_usage['visits_available'] = $cycle_usage['threshold'] ? $cycle_usage['threshold'] - $cycle_usage['visits'] : -1; // get used threshold info if ( $cycle_usage['threshold'] > 0 ) { $threshold_used = ( $cycle_usage['visits'] / $cycle_usage['threshold'] ) * 100; if ( $threshold_used > 100 ) $threshold_used = 100; } else $threshold_used = 0; // CN_DEV_MODE: override usage % for testing. Param: ?cn_usage=0-100 if ( defined( 'CN_DEV_MODE' ) && CN_DEV_MODE && current_user_can( 'manage_options' ) && isset( $_GET['cn_usage'] ) ) { $cn_usage_override = (int) $_GET['cn_usage']; if ( $cn_usage_override >= 0 && $cn_usage_override <= 100 ) { $threshold_used = $cn_usage_override; if ( $cycle_usage['threshold'] <= 0 ) $cycle_usage['threshold'] = 10000; $cycle_usage['visits'] = (int) round( $cycle_usage['threshold'] * ( $threshold_used / 100 ) ); $cycle_usage['visits_available'] = $cycle_usage['threshold'] - $cycle_usage['visits']; } } $chartdata = [ 'usage' => [ 'type' => 'doughnut', 'options' => [ 'responsive' => true, 'plugins' => [ 'legend' => [ 'position' => 'top' ] ], 'hover' => [ 'mode' => 'label' ], 'layout' => [ 'padding' => 0 ] ], 'data' => [ 'labels' => [ _x( 'Used', 'threshold limit', 'cookie-notice' ), _x( 'Free', 'threshold limit', 'cookie-notice' ) ], 'datasets' => [ [ 'data' => [ $cycle_usage['visits'], $cycle_usage['visits_available'] ], 'backgroundColor' => [ 'rgb(32, 193, 158)', 'rgb(235, 233, 235)' ] ] ] ] ], 'consent-activity' => [ 'type' => 'line', 'options' => [ 'maintainAspectRatio' => false, 'responsive' => true, 'scales' => [ 'x' => [ 'display' => true, 'title' => [ 'display' => false ] ], 'y' => [ 'display' => true, 'grace' => 0, 'beginAtZero' => true, 'title' => [ 'display' => false ], 'ticks' => [ 'precision' => 0, 'maxTicksLimit' => 12 ] ] ] ] ], 'privacy-consent-logs-activity' => [ 'type' => 'line', 'options' => [ 'maintainAspectRatio' => false, 'responsive' => true, 'scales' => [ 'x' => [ 'display' => true, 'title' => [ 'display' => false ] ], 'y' => [ 'display' => true, 'grace' => 0, 'beginAtZero' => true, 'title' => [ 'display' => false ], 'ticks' => [ 'precision' => 0, 'maxTicksLimit' => 12 ] ] ], 'plugins' => [ 'legend' => [ 'display' => false ] ] ] ] ]; // warning usage color if ( $threshold_used > 80 && $threshold_used < 100 ) $chartdata['usage']['data']['datasets'][0]['backgroundColor'][0] = 'rgb(255, 193, 7)'; // danger usage color elseif ( $threshold_used == 100 ) $chartdata['usage']['data']['datasets'][0]['backgroundColor'][0] = 'rgb(220, 53, 69)'; $consent_activity_data = [ 'labels' => [], 'datasets' => [ 0 => [ 'label' => sprintf( __( 'Level %s', 'cookie-notice' ), 1 ), 'data' => [], 'fill' => true, 'backgroundColor' => 'rgba(196, 196, 196, 0.3)', 'borderColor' => 'rgba(196, 196, 196, 1)', 'borderWidth' => 1.2, 'borderDash' => [], 'pointBorderColor' => 'rgba(196, 196, 196, 1)', 'pointBackgroundColor' => 'rgba(255, 255, 255, 1)', 'pointBorderWidth' => 1.2 ], 1 => [ 'label' => sprintf( __( 'Level %s', 'cookie-notice' ), 2 ), 'data' => [], 'fill' => true, 'backgroundColor' => 'rgba(213, 181, 101, 0.3)', 'borderColor' => 'rgba(213, 181, 101, 1)', 'borderWidth' => 1.2, 'borderDash' => [], 'pointBorderColor' => 'rgba(213, 181, 101, 1)', 'pointBackgroundColor' => 'rgba(255, 255, 255, 1)', 'pointBorderWidth' => 1.2 ], 2 => [ 'label' => sprintf( __( 'Level %s', 'cookie-notice' ), 3 ), 'data' => [], 'fill' => true, 'backgroundColor' => 'rgba(152, 145, 177, 0.3)', 'borderColor' => 'rgba(152, 145, 177, 1)', 'borderWidth' => 1.2, 'borderDash' => [], 'pointBorderColor' => 'rgba(152, 145, 177, 1)', 'pointBackgroundColor' => 'rgba(255, 255, 255, 1)', 'pointBorderWidth' => 1.2 ] ] ]; // generate chart days $chart_date_format = 'j/m'; for ( $i = 29; $i >= 0; $i-- ) { // set label $consent_activity_data['labels'][] = date( $chart_date_format, strtotime( '-'. ( $i + 1 ) .' days' ) ); // reset datasets $consent_activity_data['datasets'][0]['data'][] = 0; $consent_activity_data['datasets'][1]['data'][] = 0; $consent_activity_data['datasets'][2]['data'][] = 0; } if ( ! empty( $analytics['consentActivities'] ) && is_array( $analytics['consentActivities'] ) ) { // set consent records in charts days foreach ( $analytics['consentActivities'] as $index => $entry ) { $time = date_i18n( $chart_date_format, strtotime( $entry->eventdt ) ); $i = array_search( $time, $consent_activity_data['labels'] ); if ( $i !== false ) $consent_activity_data['datasets'][(int) $entry->consentlevel - 1]['data'][$i] = (int) $entry->totalrecd; } } $chartdata['consent-activity']['data'] = $consent_activity_data; $privacy_consent_logs_activity_data = [ 'labels' => [], 'datasets' => [ 0 => [ 'label' => __( 'Privacy Content Logs', 'cookie-notice' ), 'data' => [], 'fill' => true, 'backgroundColor' => 'rgba(32, 193, 158, 0.3)', 'borderColor' => 'rgba(32, 193, 158, 1)', 'borderWidth' => 1.2, 'borderDash' => [], 'pointBorderColor' => 'rgba(32, 193, 158, 1)', 'pointBackgroundColor' => 'rgba(255, 255, 255, 1)', 'pointBorderWidth' => 1.2 ] ] ]; for ( $i = 29; $i >= 0; $i-- ) { // set label $privacy_consent_logs_activity_data['labels'][] = date( $chart_date_format, strtotime( '-'. ( $i + 1 ) .' days' ) ); // reset dataset $privacy_consent_logs_activity_data['datasets'][0]['data'][] = 0; } if ( ! empty( $analytics['privacyActivities'] ) && is_array( $analytics['privacyActivities'] ) ) { // set consent records in charts days foreach ( $analytics['privacyActivities'] as $index => $entry ) { $time = date_i18n( $chart_date_format, strtotime( $entry->date ) ); $i = array_search( $time, $privacy_consent_logs_activity_data['labels'] ); if ( $i !== false ) $privacy_consent_logs_activity_data['datasets'][0]['data'][$i] = (int) $entry->count; } } $chartdata['privacy-consent-logs-activity']['data'] = $privacy_consent_logs_activity_data; // prepare script data $script_data = [ 'ajaxURL' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'cn-dashboard-widget' ), 'nonceUser' => wp_create_nonce( 'cn-dashboard-user-options' ), 'charts' => $chartdata ]; wp_add_inline_script( 'cookie-notice-admin-dashboard', 'var cnDashboardArgs = ' . wp_json_encode( $script_data ) . ";\n", 'before' ); } /** * Render dashboard widget. * * @return void */ public function dashboard_widget() { // get main instance $cn = Cookie_Notice(); if ( $cn->is_network_admin() ) $upgrade_url = network_admin_url( 'admin.php?page=cookie-notice&welcome=1' ); else $upgrade_url = admin_url( 'admin.php?page=cookie-notice&welcome=1' ); $html = ''; // compliance active, display chart if ( $cn->get_status() === 'active' ) { // get user options $user_options = get_user_meta( get_current_user_id(), 'pvc_dashboard', true ); // empty options? if ( empty( $user_options ) || ! is_array( $user_options ) ) $user_options = []; // sanitize options $user_options = map_deep( $user_options, 'sanitize_text_field' ); // get menu items $menu_items = ! empty( $user_options['menu_items'] ) ? $user_options['menu_items'] : []; $items = [ [ 'id' => 'visits', 'title' => esc_html__( 'Traffic Overview', 'cookie-notice' ), 'description' => esc_html__( 'Displays the general visits information for your domain.', 'cookie-notice' ) ], [ 'id' => 'consent-activity', 'title' => esc_html__( 'Cookie Consent Activity', 'cookie-notice' ), 'description' => esc_html__( 'Displays the chart of the domain cookie consent activity in the last 30 days.', 'cookie-notice' ) ], [ 'id' => 'privacy-consent-logs-activity', 'title' => esc_html__( 'Privacy Consent Activity', 'cookie-notice' ), 'description' => esc_html__( 'Displays the chart of the domain privacy consent activity in the last 30 days.', 'cookie-notice' ) ] ]; $html .= '
' . esc_html( sprintf( __( 'Visits usage: %1$s / %2$s', 'cookie-notice' ), $cycle_usage['visits'], $cycle_usage['threshold'] ) ) . '
' . esc_html( sprintf( __( 'Cycle started: %s', 'cookie-notice' ), date_i18n( $date_format, $cycle_usage['start_date']->getTimestamp() ) ) ) . '
' . esc_html( sprintf( __( 'Days to go: %s', 'cookie-notice' ), $cycle_usage['days_to_go'] ) ) . '
' . esc_html( $cn_dash_desc ) . '