Add these in your theme’s functions.php or a small plugin. Hooks used only to wire the free plugin and Pro together are left out.
The fast endpoint and filters
Vireo records each view through a small endpoint that loads WordPress without your plugins or theme, so it’s fast. Code you add can’t run there. If you use any of these filters, Vireo notices and records views through the standard admin-ajax.php route instead, which is slower but sees your code:
vireo_trust_proxy_headers, vireo_beacon_rate_limit_per_minute, vireo_beacon_rate_limit_shard_keys, vireo_honor_opt_out, vireo_bot_ua_pattern, vireo_bot_signatures, vireo_geo_country_headers, vireo_buffer_dir_max_bytes, vireo_headless_allowed_origins.
Before Vireo Analytics 0.12.5, vireo_beacon_rate_limit_shard_keys, vireo_buffer_dir_max_bytes and vireo_bot_signatures were missing from that check, so setting one of them left views on the fast endpoint, where it had no effect. From 0.12.5 they switch the route like the others.
| Hook |
Type |
Arguments |
What it does |
vireo_force_direct_endpoint |
filter |
bool|null $force (default null) |
false records every view through admin-ajax.php. true uses the fast endpoint without testing it first, for hosts that block a site’s requests to itself. It can’t override the filters above, or an endpoint address on another host. |
vireo_endpoint_url |
filter |
string $url |
The address the tracker sends views to. Defaults to the plugin’s endpoint.php. If it points at another host, for example because a CDN rewrote it, Vireo uses admin-ajax.php instead. |
Vireo checks the endpoint when it’s activated and then once an hour, so a change to either filter takes effect at the next check.
Tracking
| Hook |
Type |
Arguments |
What it does |
vireo_load_tracking_script |
filter |
bool $load (default true) |
Return false to keep the tracker off the current page. |
vireo_print_tracking_script |
action |
none |
Call it with do_action() before </body> in a template that has no wp_footer(). It prints the tracker once. |
vireo_honor_opt_out |
filter |
bool $honor (default true) |
Return false to count visitors who send Do Not Track or Global Privacy Control. |
vireo_require_consent |
filter |
bool $require (default false) |
Return true to wait for statistics consent from a WP Consent API plugin. |
vireo_collect_web_vitals |
filter |
bool $collect (default true) |
Return false to stop collecting Core Web Vitals. |
vireo_auto_event_download_exts |
filter |
string $exts, extensions joined by | |
The file types the File downloads auto-event records. Default pdf|zip|rar|7z|doc|docx|xls|xlsx|ppt|pptx|csv|mp3|mp4|mov|wav|dmg|pkg|exe|apk. |
vireo_track_wpra |
filter |
bool $track (default true) |
Return false to stop counting clicks on WP RSS Aggregator items. |
vireo_track_spotlight |
filter |
bool $track (default true) |
Return false to stop counting Spotlight feed clicks. |
vireo_show_admin_bar |
filter |
bool $show, int $user_id |
Whether the toolbar shows today’s pageviews for this user. Starts from the Toolbar setting. |
// Keep the tracker off a landing page used for ad tests.
add_filter( 'vireo_load_tracking_script', function ( $load ) {
return is_page( 'ad-test' ) ? false : $load;
} );
Bots and counting
| Hook |
Type |
Arguments |
What it does |
vireo_bot_ua_pattern |
filter |
string $pattern, a regular expression without delimiters |
Replace the whole bot pattern. Matches are reported as Other bots. |
vireo_bot_signatures |
filter |
array $signatures, category to combined regex |
The extended bot list, generated from Matomo Device Detector. Return an empty array to skip it and keep only Vireo’s own list. |
vireo_visitor_path_cap |
filter |
int $cap (default 5) |
Most views of one page a visitor can add in a day. |
vireo_visitor_daily_cap |
filter |
int $cap (default 50) |
Most views a visitor can add in a day. |
vireo_beacon_rate_limit_per_minute |
filter |
int $limit (default 60) |
Pageviews accepted per minute from one address. 0 or less turns the limit off. |
vireo_beacon_rate_limit_shard_keys |
filter |
int $keys (default 2000) |
How many addresses each rate-limit file remembers before the oldest are dropped. 0 or less keeps them all. See the fast endpoint. |
vireo_ai_sources |
filter |
array $map, label to host regex |
The AI assistants recognised as referrers. |
// Recognise another assistant as an AI referrer.
add_filter( 'vireo_ai_sources', function ( $map ) {
$map['Example AI'] = '(^|\.)example-ai\.com$';
return $map;
} );
Proxies and addresses
| Hook |
Type |
Arguments |
What it does |
vireo_trust_proxy_headers |
filter |
bool $trust (default false) |
Return true to read the visitor’s address from CF-Connecting-IP, X-Forwarded-For or X-Real-IP when the request comes from a trusted proxy. |
vireo_trusted_proxies |
filter |
array $cidrs |
Networks whose forwarding headers are believed. Defaults to loopback, private ranges and Cloudflare. |
vireo_geo_country_headers |
filter |
array $headers |
$_SERVER keys read for a country code from your host or CDN, such as HTTP_CF_IPCOUNTRY. |
add_filter( 'vireo_trust_proxy_headers', '__return_true' );
add_filter( 'vireo_trusted_proxies', function ( $cidrs ) {
$cidrs[] = '203.0.113.0/24'; // Your load balancer.
return $cidrs;
} );
Headless and connected sites
| Hook |
Type |
Arguments |
What it does |
vireo_headless_post_id |
filter |
int $post_id, string $path, string $site, int $claimed |
Map a front-end path to a post when matching by path can’t. $site is the front end’s origin and $claimed the ID the page declared. |
vireo_headless_allowed_origins |
filter |
array $origins |
Origins allowed to send pageviews with the headless tag. Starts with the “Front-end site address” setting. |
vireo_connected_sites_limit |
filter |
int $limit (default 1) |
How many connected sites this install allows, capped at 100. |
vireo_mainwp_enabled |
filter |
bool $enabled (default true) |
Return false to stop a MainWP dashboard reading this site’s numbers. |
vireo_mainwp_proxied_abilities |
filter |
string[] $names |
The reports a MainWP dashboard may run on this site. Starts with Vireo’s own read-only abilities, and Pro adds its reports. Only read-only abilities run, whatever the list says, and get-sites and get-sites-overview never do. |
// Front end serves posts under /blog/ while WordPress has them at the root.
add_filter( 'vireo_headless_post_id', function ( $post_id, $path ) {
if ( $post_id || 0 !== strpos( $path, '/blog/' ) ) {
return $post_id;
}
return url_to_postid( home_url( substr( $path, 5 ) ) );
}, 10, 2 );
REST API, abilities and MCP
| Hook |
Type |
Arguments |
What it does |
vireo_rest_permission_callback |
filter |
bool $allowed, WP_REST_Request $request |
Add a condition to the REST API. Runs only after the capability check passes, so it can narrow access, never widen it. |
vireo_abilities_permission_callback |
filter |
bool $allowed, array $input |
The same for abilities and MCP tools. |
vireo_mcp_tools |
filter |
array $tools, ability names |
The abilities offered as tools on the MCP server. Pro adds its own through this filter. |
vireo_mcp_server_description |
filter |
string $description |
The description the MCP server gives AI assistants when they connect. |
Dashboard and data
| Hook |
Type |
Arguments |
What it does |
vireo_annotation_capability |
filter |
string $cap (default edit_others_posts) |
The capability needed to add notes. |
vireo_drivers_limit |
filter |
int $limit |
How many movers What changed lists each way: 3 in free, 10 with Pro. |
vireo_overview_card_tab |
filter |
string $tab, callable $cb |
Which Overview tab an add-on card hooked to vireo_overview_after_core appears on: content, campaigns, speed or issues. |
vireo_overview_tab_{tab} |
action |
string $start, string $end, bool $compare |
Print a card on one Overview tab: vireo_overview_tab_content, _campaigns, _speed or _issues. |
vireo_email_brand |
filter |
array $brand with logo_url (string, default empty), accent (hex colour like #0f172a, the default; anything else falls back to it) and show_vireo (bool, default true) |
How the email digest looks: a logo above the heading, the colour of the “View full dashboard” button, and whether the footer names Vireo Analytics. Vireo Pro’s white-label settings use it. |
vireo_hour_stats_retention_days |
filter |
int $days (default 7, 1 to 90) |
How long hourly traffic is kept for the Hour chart. |
vireo_plausible_max_bytes |
filter |
int $bytes (default 1 GB) |
The most a Plausible export may unpack to. |
vireo_after_flush |
action |
none |
Fires after each batch of new views reaches the database, about once a minute. |
vireo_goal_completed |
action |
int $goal_id, string $visitor_hash, int $ts, float $value, string $date |
Fires for each goal completion as it’s recorded, with the visitor’s salted hash (empty when there isn’t one), the Unix time, the goal’s value and the site-local date. It’s the only point where a completion still carries its visitor, so listen here for sequences. The hash changes every day and identifies no one. |
vireo_allowed_query_vars |
filter |
string[] $keys (default page_id, p, tag, cat, product, attachment_id) |
Query parameters kept in a page’s path. Every other parameter is dropped, so /pricing/?ref=mail counts as /pricing/. |
vireo_404_max_new_rows_per_day |
filter |
int $max (default 500) |
How many new Broken links entries are recorded in a day, each a missing address and where it was linked from. Hits on entries already recorded that day still count. 0 or less removes the limit. |
vireo_buffer_dir_max_bytes |
filter |
int $bytes (default 250 MB) |
The most Vireo’s data folder may hold while views wait to be saved, across this site and its connected sites. Past it, new views are dropped until saving catches up. It’s reached only when saving has stopped, which Site Health reports. See the fast endpoint. |
vireo_network_activation_limit |
filter |
int $limit (default 200, 1 to 10000) |
How many sites network activation sets up straight away. The rest set themselves up the first time one of their pages loads. |
Functions
vireo_track_event( string $name, string $value = '' ): bool
Records a custom event from PHP. The name keeps only a-z, 0-9, _ and -, and name and value are cut to 100 characters. Returns false if the name is empty after cleaning. See Events and broken links.
Pro
| Hook |
Type |
Arguments |
What it does |
vireo_tracked_taxonomies |
filter |
string[] $taxonomies (default category, post_tag) |
The taxonomies in Top categories and tags. |
vireo_download_extensions |
filter |
string[] $extensions, lowercase, no dot |
File types Pro counts as downloads. |
vireo_page_vitals_retention_days |
filter |
int $days (default 180, 30 to 3650) |
How long per-page speed is kept. |
vireo_transitions_retention_days |
filter |
int $days (default 90, 1 to 730) |
How long page-to-page paths are kept. |
vireo_funnel_retention_days |
filter |
int $days (default 30, 1 to 365) |
How long funnel step records are kept. |
vireo_transitions_max_new_pairs_per_day |
filter |
int $max (default 2000) |
How many new page-to-page pairs Where people go next records in a day. Pairs already recorded still count. 0 or less removes the limit. |
vireo_ai_report_content |
filter |
string $html, array $data |
The AI-written part of the Pro email report, before it goes into the email. |
vireo_ai_model_preference |
filter |
string[] $models |
The models the Pro email report and Ask Vireo ask your AI provider for, in order of preference. |
vireo_ask_tools |
filter |
string[] $tools |
The abilities Ask Vireo may use. Only names starting with vireo-analytics/get- are kept. |
vireo_ask_system_prompt |
filter |
string $prompt, string[] $tools |
The instruction Ask Vireo starts each question with. |
vireo_pro_site_abilities |
filter |
string[] $tools |
The abilities that take a site argument for connected sites. Add one only if every table it reads follows the site being asked about, or it answers with this site’s numbers. |
vireo_mainwp_timeout |
filter |
int $seconds (default 10) |
How long a MainWP child gets to answer an AI assistant’s question. |