*/
const RANGES = array(
'7d' => 7,
'30d' => 30,
'90d' => 90,
);
/**
* Register hooks.
*
* @return void
*/
public function hooks() {
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
}
/**
* Enqueue the dashboard's local CSS/JS, but only on the dashboard screen.
*
* @param string $hook Current admin page hook suffix.
* @return void
*/
public function enqueue_assets( $hook ) {
if ( self::HOOK !== $hook ) {
return;
}
wp_enqueue_style( self::HANDLE, ADPRIVA_PLUGIN_URL . 'assets/css/dashboard.css', array(), ADPRIVA_VERSION );
wp_enqueue_script( self::HANDLE, ADPRIVA_PLUGIN_URL . 'assets/js/dashboard.js', array(), ADPRIVA_VERSION, true );
}
/**
* Render the top-level page: the dashboard when connected, otherwise a Connect
* call-to-action.
*
* @return void
*/
public static function render() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
if ( ! Adpriva_Tokens::is_connected() ) {
self::render_connect_screen();
return;
}
$range = self::current_range();
$window = self::window_for( $range );
$summary = Adpriva_API::summary( $window['from'], $window['to'] );
echo '
';
echo '
' . esc_html__( 'AdPriva', 'adpriva' ) . '
';
self::render_range_form( $range );
if ( is_wp_error( $summary ) ) {
echo '
' . esc_html__( "We couldn't load your dashboard right now. Please try again shortly.", 'adpriva' ) . '
';
echo '
';
return;
}
self::render_cards( $summary );
self::render_breakdown( $summary );
$series = Adpriva_API::timeseries( $window['from'], $window['to'] );
$points = ( ! is_wp_error( $series ) && isset( $series['points'] ) && is_array( $series['points'] ) ) ? $series['points'] : array();
self::render_chart( $points );
printf(
'%2$s
',
esc_url( Adpriva_Config::console_url() ),
esc_html__( 'Open the full AdPriva console →', 'adpriva' )
);
echo '';
}
/**
* The validated active range: a valid ?range= wins, else the configured default.
*
* @return string
*/
public static function current_range() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only view state; no data is mutated.
$requested = isset( $_GET['range'] ) ? sanitize_text_field( wp_unslash( $_GET['range'] ) ) : '';
if ( isset( self::RANGES[ $requested ] ) ) {
return $requested;
}
$default = Adpriva_Config::default_range();
return isset( self::RANGES[ $default ] ) ? $default : '30d';
}
/**
* The span (in days) for a range key, defaulting to 30.
*
* @param string $range Range key.
* @return int
*/
public static function days_for( $range ) {
return isset( self::RANGES[ $range ] ) ? self::RANGES[ $range ] : 30;
}
/**
* The [from, to] YYYY-MM-DD window for a range, ending today (UTC).
*
* @param string $range Range key.
* @return array{from: string, to: string}
*/
public static function window_for( $range ) {
$days = self::days_for( $range );
$now = time();
return array(
'from' => gmdate( 'Y-m-d', $now - ( $days * DAY_IN_SECONDS ) ),
'to' => gmdate( 'Y-m-d', $now ),
);
}
/**
* Render the range selector (a GET form that reloads the page with ?range=).
*
* @param string $active Active range key.
* @return void
*/
private static function render_range_form( $active ) {
$labels = array(
'7d' => __( 'Last 7 days', 'adpriva' ),
'30d' => __( 'Last 30 days', 'adpriva' ),
'90d' => __( 'Last 90 days', 'adpriva' ),
);
echo '';
}
/**
* Render the KPI cards from the summary payload.
*
* @param array $summary Summary response.
* @return void
*/
private static function render_cards( array $summary ) {
$cards = array(
__( 'Verified events', 'adpriva' ) => self::num( $summary, 'total_count' ),
__( 'No automation found', 'adpriva' ) => self::num( $summary, 'human_count' ),
__( 'AI agent', 'adpriva' ) => self::num( $summary, 'authorized_agent_count' ),
__( 'Automation detected', 'adpriva' ) => self::num( $summary, 'abusive_bot_count' ),
);
echo '';
foreach ( $cards as $label => $value ) {
printf(
'
%1$s%2$s
',
esc_html( number_format_i18n( $value ) ),
esc_html( $label )
);
}
echo '
';
}
/**
* Render the verdict breakdown list.
*
* @param array $summary Summary response.
* @return void
*/
private static function render_breakdown( array $summary ) {
$rows = array(
__( 'No automation found', 'adpriva' ) => self::num( $summary, 'human_count' ),
__( 'AI agent', 'adpriva' ) => self::num( $summary, 'authorized_agent_count' ),
__( 'Automation detected', 'adpriva' ) => self::num( $summary, 'abusive_bot_count' ),
__( 'Possible automation', 'adpriva' ) => self::num( $summary, 'uncertain_count' ),
);
echo '' . esc_html__( 'Check results', 'adpriva' ) . '
';
echo '';
foreach ( $rows as $label => $value ) {
printf(
'- %1$s %2$s
',
esc_html( $label ),
esc_html( number_format_i18n( $value ) )
);
}
echo '
';
}
/**
* Render the trend chart container with the series as a JSON data island that
* the bundled dashboard.js reads and draws as an inline SVG.
*
* @param array> $points Per-day series.
* @return void
*/
private static function render_chart( array $points ) {
echo '' . esc_html__( 'Traffic trend', 'adpriva' ) . '
';
printf(
'',
esc_attr( (string) wp_json_encode( array_values( $points ) ) )
);
}
/**
* Render the not-connected Connect call-to-action.
*
* @return void
*/
private static function render_connect_screen() {
echo '';
echo '
' . esc_html__( 'AdPriva', 'adpriva' ) . '
';
echo '
' . esc_html__( 'Connect this site to AdPriva to verify your ad traffic and see your dashboard here.', 'adpriva' ) . '
';
echo '
';
echo '
';
}
/**
* Read an integer metric from the summary payload.
*
* @param array $summary Summary response.
* @param string $key Metric key.
* @return int
*/
private static function num( array $summary, $key ) {
return isset( $summary[ $key ] ) ? (int) $summary[ $key ] : 0;
}
}