Developers
Every filter and action with its signature and an example, the REST API under acid-aeo/v1, the WP-CLI commands, and the ai-context JSON schema.
Updated 2026-10-08 · applies to Acid AEO 1.0.4
Acid AEO has 13 filters and 2 actions, an administrative REST API and eight WP-CLI commands. All hook names start with acid_aeo_. The examples go in a small plugin or in your theme's functions.php.
Filters
acid_aeo_ai_context_data
Filters the site profile ai-context.json is built from. Parameters: array $data. Key pages sit under key_pages here and are published as keyPages.
add_filter( 'acid_aeo_ai_context_data', function ( $data ) {
$data['key_pages'][] = [
'title' => 'Pricing',
'url' => home_url( '/pricing/' ),
'summary' => 'Plans and what each one includes.',
];
return $data;
} );
acid_aeo_ai_txt_data
Filters the policy ai.txt is built from. Parameters: array $data. The contact key becomes the Contact line.
add_filter( 'acid_aeo_ai_txt_data', function ( $data ) {
$data['contact'] = '[email protected]';
return $data;
} );
acid_aeo_humans_data
Filters the colophon humans.txt is built from. Parameters: array $data. thanks is a list of names.
add_filter( 'acid_aeo_humans_data', function ( $data ) {
$data['thanks'][] = 'The WordPress community';
return $data;
} );
acid_aeo_indexnow_endpoint
Filters the IndexNow API endpoint. Parameters: string $endpoint, default https://api.indexnow.org/indexnow.
add_filter( 'acid_aeo_indexnow_endpoint', function ( $endpoint ) {
return 'https://www.bing.com/indexnow';
} );
acid_aeo_is_noindex
Filters whether a post counts as noindex. Parameters: bool $noindex, int $post_id. A post that counts as noindex is left out of the generated files.
add_filter( 'acid_aeo_is_noindex', function ( $noindex, $post_id ) {
if ( 'landing' === get_post_type( $post_id ) ) {
return true;
}
return $noindex;
}, 10, 2 );
acid_aeo_last_updated_html
Filters the "Updated on" paragraph before it reaches the content. Parameters: string $html (already escaped), WP_Post $post. An empty string drops the line.
add_filter( 'acid_aeo_last_updated_html', function ( $html, $post ) {
if ( has_category( 'news', $post ) ) {
return '';
}
return $html;
}, 10, 2 );
acid_aeo_last_updated_threshold
Filters how far apart publishing and revising have to be, in seconds. Parameters: int $threshold (default DAY_IN_SECONDS), WP_Post $post. Zero makes every revision count.
add_filter( 'acid_aeo_last_updated_threshold', function ( $threshold, $post ) {
return WEEK_IN_SECONDS;
}, 10, 2 );
acid_aeo_llms_data
Filters the site summary llms.txt and llms-full.txt are built from. Parameters: array $data. sections is a list of title and items; the first section is Key pages.
add_filter( 'acid_aeo_llms_data', function ( $data ) {
$data['sections'][0]['items'][] = [
'title' => 'Pricing',
'url' => home_url( '/pricing/' ),
'summary' => 'Plans and what each one includes.',
];
return $data;
} );
acid_aeo_llms_full_documents
Filters how many documents llms-full.txt considers before the byte budget (llms.full_max_bytes) applies. Parameters: int $limit, default 200. Key pages are added on top; the result is at least 1.
add_filter( 'acid_aeo_llms_full_documents', function ( $limit ) {
return 500;
} );
acid_aeo_loopback_args
Filters the arguments of an audit loopback request, for a host that needs a longer timeout, an extra header or basic auth to answer its own requests. Parameters: array $args (for wp_remote_get()), string $url.
add_filter( 'acid_aeo_loopback_args', function ( $args, $url ) {
$args['headers']['Authorization'] = 'Basic ' . base64_encode( 'staging:secret' );
$args['timeout'] = 20;
return $args;
}, 10, 2 );
acid_aeo_schema_context
Filters the facts the JSON-LD graph is built from. Parameters: array $ctx, with the keys site, page and pieces. pieces maps each piece (organization, website, webpage, breadcrumb, article, person, faq, speakable, image_meta) to true or false.
add_filter( 'acid_aeo_schema_context', function ( $ctx ) {
if ( is_page( 'contact' ) ) {
$ctx['pieces']['speakable'] = false;
}
return $ctx;
} );
acid_aeo_schema_graph
Filters the finished JSON-LD graph. Parameters: array $graph, holding @context and @graph, or empty when there is nothing to print. Returning an empty array prints nothing.
add_filter( 'acid_aeo_schema_graph', function ( $graph ) {
if ( isset( $graph['@graph'] ) && is_front_page() ) {
$graph['@graph'][] = [
'@type' => 'Service',
'name' => 'Website audits',
'provider' => [ '@id' => home_url( '/#organization' ) ], // a personal site uses /#person
];
}
return $graph;
} );
acid_aeo_security_data
Filters the contact details security.txt is built from. Parameters: array $data. contact is a list; a bare email address becomes a mailto: URI.
add_filter( 'acid_aeo_security_data', function ( $data ) {
$data['contact'][] = 'https://example.com/security/';
return $data;
} );
Actions
acid_aeo_daily_tasks fires once a day, from the acid_aeo_daily cron event scheduled on activation. No parameters. The plugin itself uses it to prune old citation events, renew the security.txt expiry date and rewrite the static files.
add_action( 'acid_aeo_daily_tasks', function () {
delete_transient( 'my_llms_report' );
} );
acid_aeo_settings_updated fires after settings are saved. Parameters: string $section, the section that changed, or * after an import replaced all of them. It fires for saves from the settings screen, each wizard step and the audit's fixes. A single value the plugin writes internally (the wizard's progress, a key generated on boot) does not fire it; the audit fix for the key does.
add_action( 'acid_aeo_settings_updated', function ( $section ) {
if ( in_array( $section, [ 'llms', 'identity', '*' ], true ) ) {
my_cdn_purge( [ '/llms.txt', '/llms-full.txt' ] );
}
} );
REST API
Base: /wp-json/acid-aeo/v1/. Every route below requires the manage_options capability. From the admin, send a wp_rest nonce in the X-WP-Nonce header; from outside, authenticate with an application password.
| Route | Method | What it does |
|---|---|---|
/settings |
GET, PUT | Read every setting; save one section with data, or a sections object |
/environment |
GET | What the plugin detected about the site |
/preview/{file} |
GET | Render a file: llms, llms_full, robots, humans, ai_txt, ai_context, security; optional draft |
/audit |
GET | Run the readiness audit; fresh=1 skips the cached result |
/audit/fix/{id} |
POST | Apply one safe fix, then re-run the audit |
/wizard/step |
POST | Save one wizard step (step, data) |
/wizard/complete |
POST | Finish setup; submit_indexnow sends every URL |
/indexnow/submit |
POST | Submit urls, or all=true for the whole site; 409 while the module is off |
/indexnow/log |
GET | The last 50 submissions |
/citations/stats |
GET | Totals, agents, top pages and timeline for days (1–365, default 30) |
/citations/events |
GET | Events, newest first: page, per_page (max 200), type (crawl or referral) |
/citations/export |
GET | Every event as a CSV download |
/citations |
DELETE | Delete events; older_than_days keeps the newer ones |
/static-files/write |
POST | Write the static files now |
/cache/flush |
POST | Drop every cached file |
/export |
GET | Every setting, as JSON |
/import |
POST | Replace every setting with a settings object |
/system-info |
GET | Versions and environment for a support request |
The one public route, POST /beacon, belongs to the browser beacon of the citations module and is not meant for you to call. See Privacy.
curl -u admin:"abcd efgh ijkl mnop qrst uvwx" \
"https://example.com/wp-json/acid-aeo/v1/audit?fresh=1"
curl -u admin:"abcd efgh ijkl mnop qrst uvwx" -X POST \
-H "Content-Type: application/json" \
-d '{"urls":["https://example.com/pricing/"]}' \
https://example.com/wp-json/acid-aeo/v1/indexnow/submit
WP-CLI
wp acid-aeo audit [--fresh] [--format=<table|json>]
wp acid-aeo regenerate
wp acid-aeo indexnow <submit|log> [<url>...] [--all]
wp acid-aeo static <write|remove>
wp acid-aeo export [--file=<path>]
wp acid-aeo import <file>
wp acid-aeo citations <stats|purge> [--days=<days>] [--older-than=<days>]
wp acid-aeo preview <llms|llms_full|robots|humans|ai_txt|ai_context|security>
auditprints the findings and exits with status 1 when the score is below 50, so a deployment can gate on it.--formatdefaults totable.regeneratedrops every cached file and rebuilds the rewrite rules.indexnow submitsends the URLs given;--allqueues every published post of the configured types; exits 1 with a message while the module is off.logprints the history.static writewrites the generated files to disk;removedeletes the ones the plugin wrote.robots.txtis never touched.exportprints every setting as JSON, or writes it to--file.importreplaces every setting with an export file, sanitized on the way in.citations statsreports on the last--days(default 30);purgedeletes events older than--older-than, or all of them.previewprints what a file would say now, even with its module off.
The ai-context schema
ai-context.json names its schema in $schema: https://acidstudios.ro/schemas/ai-context/1.0.json. The plugin writes that URL and never fetches it.
The twelve top-level members are always present, in this order: $schema, version (1.0), generated, language, instructions, organization, offerings, keyPages, faq, contact, policy and links. Empty values are dropped at every depth; an empty object section is {} and an empty list is []. The instructions.generator field (Acid AEO and the version) is how the plugin recognises a copy it wrote itself.
Settings paths
All settings live in one option, acid_aeo_settings, addressed by dotted paths such as identity.name. The sections are general, identity, policy, llms, offerings, faq, humans, security, ai_context, ai_txt, schema, head, headers, indexnow, citations, content and static_files; the section name is what acid_aeo_settings_updated receives. The wizard page lists the paths each step writes. The ones most often read:
| Path | Default |
|---|---|
general.site_type |
business |
identity.name, identity.email |
empty |
policy.preset |
citable |
llms.key_pages |
empty list of post IDs |
llms.posts_limit |
20 |
llms.full_max_bytes |
2000000 |
schema.defer_to_seo |
on |
indexnow.enabled, indexnow.auto_submit |
on |
citations.beacon |
off |
citations.retention_days |
90 |
content.last_updated |
off |
static_files.enabled |
off |
Every module's switch is {section}.enabled. To read a value in PHP, use \AcidStudios\AEO\Options::get( 'identity.name' ).
Found a mistake or something missing? Write to [email protected].