Docs menuUse Vireo's abilities from your own code

Use Vireo's abilities from your own code

List Vireo's abilities, run them from PHP with wp_get_ability() or over REST through the Abilities API, and handle permissions and errors.

On this page

WordPress’s Abilities API gives every plugin one way to describe what it can do, so other code can find and call it without learning each plugin’s own API. Vireo registers its reports as abilities. Your plugin, a theme, a WP-CLI script or an AI tool can call them and get the same numbers as the dashboard.

You need WordPress 6.9 or newer, where the Abilities API is part of core.

What’s there

Vireo’s abilities are in the vireo-analytics category and named vireo-analytics/get-.... The free plugin registers 22; Vireo Pro adds its own, including get-revenue-forecast and get-subscriptions for stores. Every one is read-only. The API reference lists them all with their inputs.

List them from PHP:

foreach ( wp_get_abilities() as $ability ) {
	if ( 0 === strpos( $ability->get_name(), 'vireo-analytics/' ) ) {
		echo $ability->get_name() . ': ' . $ability->get_label() . "\n";
	}
}

Or over REST, with an application password:

curl -u "your-username:xxxx xxxx xxxx xxxx xxxx xxxx" \
  "https://example.com/wp-json/wp-abilities/v1/abilities?category=vireo-analytics&per_page=50"

Each entry includes the ability’s input schema, so you can see what it accepts.

Run one from PHP

$ability = wp_get_ability( 'vireo-analytics/get-top-pages' );
$result  = $ability ? $ability->execute( array( 'limit' => 2 ) ) : null;

if ( is_wp_error( $result ) ) {
	error_log( $result->get_error_message() );
} else {
	foreach ( $result['rows'] as $page ) {
		printf( "%d  %s\n", $page['pageviews'], $page['title'] );
	}
}

execute() returns the data as a PHP array, or a WP_Error. As JSON:

{"rows":[
  {"post_id":4,"path":"/2026/10/11/how-to-pack-for-a-month/","title":"How to pack for a month","pageviews":6,"visitors":6},
  {"post_id":6,"path":"/2026/10/11/pricing/","title":"Pricing","pageviews":3,"visitors":3}
]}

What comes back

Every ability returns an object, never a bare list:

  • Abilities that return a list put it under rows: daily stats, hourly stats, top pages, top referrers, traffic sources, countries, events, vitals, annotations and goals. Nothing to report is {"rows": []}.
  • The others return their own object, such as get-totals with pageviews, visitors, days, avg_daily, and from 0.13.0 avg_time_on_page_seconds, timed_views and bounce_rate_percent.

The shape is the same whether you call the ability from PHP, over REST or through MCP. The API reference lists what each one returns.

Run one over REST

Read-only abilities run with GET at /wp-json/wp-abilities/v1/abilities/{name}/run. The name keeps its slash. Pass input as query parameters in the input[...] form:

curl -g -u "your-username:xxxx xxxx xxxx xxxx xxxx xxxx" \
  "https://example.com/wp-json/wp-abilities/v1/abilities/vireo-analytics/get-totals/run?input[start]=2026-09-12&input[end]=2026-10-11"
{"pageviews":15,"visitors":15,"days":30,"avg_daily":1,"avg_time_on_page_seconds":null,"timed_views":0,"bounce_rate_percent":null}

curl’s -g stops it reading the square brackets as a pattern.

With no input at all, an ability uses its defaults:

curl -u "your-username:xxxx xxxx xxxx xxxx xxxx xxxx" \
  "https://example.com/wp-json/wp-abilities/v1/abilities/vireo-analytics/get-traffic-sources/run"

What doesn’t work:

  • POST returns 405, “Read-only abilities require GET method.”
  • ?input={"limit":1} as one JSON string returns 400, “input is not of type object”. Use input[limit]=1.
  • An input the ability doesn’t declare returns 400, for example “foo is not a valid property of Object”.

Inputs and defaults

  • start and end, as YYYY-MM-DD, default to the last 30 days in your site’s timezone. Unlike the /stats/ REST routes, they’re optional.
  • limit runs from 1 to 100. Each ability has its own default.
  • Some abilities need one more input, such as post_id for get-post-stats or host for get-referrer-detail. The reference marks which.
  • Anything else is refused. An undeclared input key makes execute() return a WP_Error with the code ability_invalid_input, rather than being ignored.

Permissions

An ability runs as the current user, and Vireo checks the same capability as the dashboard, view_vireo_analytics. In PHP, that’s whoever is logged in for the request. For a cron job or WP-CLI, there’s no user unless you set one:

wp_set_current_user( $user_id_with_dashboard_access );

Without the capability, execute() returns a WP_Error with the code ability_invalid_permissions, and REST answers 401 or 403.

Pro’s abilities also need an active Vireo Pro license, and the store abilities need a supported store to be active: WooCommerce, Easy Digital Downloads, FluentCart, Freemius, Paid Memberships Pro, Restrict Content, MemberPress, LifterLMS, GiveWP or SureCart. Where those aren’t met, the abilities aren’t registered, so wp_get_ability() returns null. The one exception is get-goals, which the free plugin registers everywhere and refuses without Pro.

To narrow access further, for example to a list of users, use the vireo_abilities_permission_callback filter. It can refuse a call; it can’t grant one to a user without the capability.

Strings from visitors

Paths, search terms, referrers and event values can be set by anyone who sends a request to your site. Before any ability returns them, Vireo strips control characters, line breaks and brackets, and cuts long values short. They’re safe to show to an AI model as data, but treat them as untrusted text in your own HTML: escape them as you would any user input.

Updated 19 October 2026. Something wrong or missing? Tell us.