{"id":310703,"date":"2026-05-26T08:01:54","date_gmt":"2026-05-26T08:01:54","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/ai-valve\/"},"modified":"2026-05-26T08:01:29","modified_gmt":"2026-05-26T08:01:29","slug":"ai-valve","status":"publish","type":"plugin","link":"https:\/\/pcd.wordpress.org\/plugins\/ai-valve\/","author":3803,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.1.6","stable_tag":"1.1.6","tested":"7.0","requires":"7.0","requires_php":"8.3","requires_plugins":null,"header_name":"AI Valve","header_author":"Per S\u00f8derlind","header_description":"Control, meter, and permission-gate AI usage from plugins that connect through the WordPress 7 AI connector.","assets_banners_color":"134d4f","last_updated":"2026-05-26 08:01:29","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/github.com\/soderlind\/ai-valve","header_author_uri":"https:\/\/soderlind.no","rating":0,"author_block_rating":0,"active_installs":0,"downloads":37,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.1.6":{"tag":"1.1.6","author":"PerS","date":"2026-05-26 08:01:29"}},"upgrade_notice":{"0.4.0":"<p>Admin UI rebuilt with React for faster, client-side rendering.<\/p>","0.3.0":"<p>Dashboard enhancements: model filter, provider+model breakdown, per-plugin bar chart, side-by-side layout.<\/p>","0.2.0":"<p>Bug fixes for log status storage and filtering. New: date range filter, context breakdown, per-plugin alerts, CSV export.<\/p>","0.1.0":"<p>Initial release.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3548717,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3548717,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256},"icon.svg":{"filename":"icon.svg","revision":3548717,"resolution":false,"location":"assets","locale":false}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3548717,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3548717,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250},"banner.svg":{"filename":"banner.svg","revision":3548717,"resolution":false,"location":"assets","locale":false}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.1.6"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3548717,"resolution":"1","location":"assets","locale":"","width":2942,"height":1844}},"screenshots":{"1":"Dashboard with usage summary cards and per-plugin breakdown."}},"plugin_section":[262246],"plugin_tags":[2353,25308,264433,258885,39819],"plugin_category":[],"plugin_contributors":[78884],"plugin_business_model":[],"class_list":["post-310703","plugin","type-plugin","status-publish","hentry","plugin_section-dashboard-widgets","plugin_tags-ai","plugin_tags-connector","plugin_tags-cost-control","plugin_tags-governance","plugin_tags-tokens","plugin_contributors-pers","plugin_committers-pers"],"banners":{"banner":"https:\/\/ps.w.org\/ai-valve\/assets\/banner-772x250.png?rev=3548717","banner_2x":"https:\/\/ps.w.org\/ai-valve\/assets\/banner-1544x500.png?rev=3548717","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":"https:\/\/ps.w.org\/ai-valve\/assets\/icon.svg?rev=3548717","icon":"https:\/\/ps.w.org\/ai-valve\/assets\/icon.svg?rev=3548717","icon_2x":false,"generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/ai-valve\/assets\/screenshot-1.png?rev=3548717","caption":"Dashboard with usage summary cards and per-plugin breakdown."}],"raw_content":"<!--section=description-->\n<p>AI Valve gives site administrators visibility and control over how plugins use the built-in WordPress AI connector.<\/p>\n\n<h4>Features<\/h4>\n\n<ul>\n<li><strong>Per-plugin access control<\/strong> \u2014 Allow or deny individual plugins from making AI requests.<\/li>\n<li><strong>Token budgets<\/strong> \u2014 Set daily and monthly token limits per plugin and globally.<\/li>\n<li><strong>Context restrictions<\/strong> \u2014 Control which execution contexts (admin, frontend, cron, REST, AJAX, CLI) may trigger AI calls.<\/li>\n<li><strong>Usage dashboard<\/strong> \u2014 See token consumption at a glance with summary cards, progress bars, and per-plugin breakdowns.<\/li>\n<li><strong>Request logging<\/strong> \u2014 Every AI request is logged with provider, model, capability, tokens, and caller attribution.<\/li>\n<li><strong>Budget alerts<\/strong> \u2014 Admin notices and optional email when usage approaches or exceeds limits.<\/li>\n<\/ul>\n\n<h4>Requirements<\/h4>\n\n<ul>\n<li>WordPress 7.0 or later<\/li>\n<li>PHP 8.3 or later<\/li>\n<li>A configured AI provider in Settings \u2192 Connectors<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Install AI Valve from the WordPress plugin directory, or upload <code>soderlind-aivalve.zip<\/code> via Plugins \u2192 Add New \u2192 Upload Plugin.<\/li>\n<li>Activate the plugin.<\/li>\n<li>Go to Settings \u2192 AI Valve to configure.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"what%20are%20tokens%3F\"><h3>What are tokens?<\/h3><\/dt>\n<dd><p>Tokens are the units AI models use to measure input and output. Roughly 1 token \u2248 \u00be of a word. Both the text you send (prompt tokens) and the text the AI returns (completion tokens) count toward your usage.<\/p><\/dd>\n<dt id=\"what%20does%20%22limit%20%3D%200%22%20mean%3F\"><h3>What does \"limit = 0\" mean?<\/h3><\/dt>\n<dd><p>A limit of 0 means unlimited \u2014 no cap is enforced. Set a positive number to restrict token usage.<\/p><\/dd>\n<dt id=\"how%20does%20ai%20valve%20identify%20which%20plugin%20made%20an%20ai%20request%3F\"><h3>How does AI Valve identify which plugin made an AI request?<\/h3><\/dt>\n<dd><p>It walks the PHP call stack (<code>debug_backtrace()<\/code>) and matches file paths against the plugins directory to determine the originating plugin slug.<\/p><\/dd>\n<dt id=\"will%20this%20work%20with%20future%20wordpress%20updates%3F\"><h3>Will this work with future WordPress updates?<\/h3><\/dt>\n<dd><p>Yes. AI Valve relies only on the stable public hooks (<code>wp_ai_client_prevent_prompt<\/code>, <code>wp_ai_client_before_generate_result<\/code>, <code>wp_ai_client_after_generate_result<\/code>) provided by the WordPress AI connector API.<\/p><\/dd>\n<dt id=\"are%20there%20developer%20hooks%3F\"><h3>Are there developer hooks?<\/h3><\/dt>\n<dd><p>Yes. See the <a href=\"https:\/\/github.com\/soderlind\/ai-valve\/blob\/main\/docs\/hooks.md\">developer hooks documentation<\/a> for available filters and actions.<\/p><\/dd>\n<dt id=\"does%20ai%20valve%20work%20on%20multisite%3F\"><h3>Does AI Valve work on multisite?<\/h3><\/dt>\n<dd><p>Yes. Each subsite has its own log table, settings, and budgets.<\/p><\/dd>\n<dt id=\"what%20happens%20when%20a%20plugin%20is%20blocked%3F\"><h3>What happens when a plugin is blocked?<\/h3><\/dt>\n<dd><p>The plugin receives a <code>WP_Error<\/code> with code <code>prompt_prevented<\/code> instead of an AI response. The denied request is logged with the reason. See <a href=\"https:\/\/github.com\/soderlind\/ai-valve\/blob\/main\/docs\/how-blocking-works.md\">how-blocking-works.md<\/a> for the full explanation.<\/p><\/dd>\n<dt id=\"how%20do%20i%20block%20all%20plugins%20and%20only%20allow%20specific%20ones%3F\"><h3>How do I block all plugins and only allow specific ones?<\/h3><\/dt>\n<dd><ol>\n<li>Go to Settings \u2192 AI Valve \u2192 Settings.<\/li>\n<li>Set the Default policy to Deny.<\/li>\n<li>Switch to the Dashboard tab.<\/li>\n<li>In the Per-plugin access table, set the plugins you want to allow to Allow.<\/li>\n<\/ol>\n\n<p>Only explicitly allowed plugins will be able to make AI requests; everything else is denied by default.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.1.6<\/h4>\n\n<ul>\n<li>Fixed: WordPress.org review issues by correcting repository URLs and restoring the <code>ai-valve<\/code> text domain.<\/li>\n<\/ul>\n\n<h4>1.1.5<\/h4>\n\n<ul>\n<li>Changed: Plugin-facing slugs, REST namespace, package metadata, docs, and admin UI prefixes from <code>ai-valve<\/code> to <code>soderlind-aivalve<\/code>.<\/li>\n<li>Fixed: Plugin text domain now uses <code>soderlind-aivalve<\/code> consistently across PHP, JavaScript, and generated assets.<\/li>\n<\/ul>\n\n<h4>1.1.4<\/h4>\n\n<ul>\n<li>Fixed: WordPress.org plugin review prefix compliance by renaming plugin-owned namespaces, constants, hooks, options, cron events, database keys, and admin script globals to the unique <code>soderlind_aivalve<\/code> prefix.<\/li>\n<li>Fixed: Migration and cleanup paths for existing <code>aivalve<\/code>\/<code>ai_valve<\/code> installs while keeping active identifiers uniquely prefixed.<\/li>\n<li>Changed: Readme tags for improved clarity and relevance.<\/li>\n<\/ul>\n\n<h4>1.1.3<\/h4>\n\n<ul>\n<li>Changed: Updated WordPress.org icons and banner.<\/li>\n<li>Fixed: Improved compatibility with custom plugin directory layouts and unique plugin-owned identifiers.<\/li>\n<li>Fixed: Resolved npm dependency security advisories.<\/li>\n<\/ul>\n\n<h4>1.1.2<\/h4>\n\n<ul>\n<li>Changed: Refactored code structure for improved readability and maintainability.<\/li>\n<\/ul>\n\n<h4>1.1.1<\/h4>\n\n<ul>\n<li>Fixed: Dashboard usage date buckets now keep Today, plugin totals, and Recent Requests aligned around database\/PHP day boundaries.<\/li>\n<li>Fixed: WordPress 6.8 SelectControl deprecation warnings in the admin UI.<\/li>\n<li>Added: WordPress.org icon and banner assets.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Removed: GitHub release updater for WordPress.org distribution.<\/li>\n<li>Removed: plugin-update-checker dependency and bundled updater files.<\/li>\n<li>Fixed: Added direct-access guards and Plugin Check cleanup for production files.<\/li>\n<\/ul>\n\n<h4>1.0.4<\/h4>\n\n<ul>\n<li>Changed: Update npm dependencies to latest versions.<\/li>\n<\/ul>\n\n<h4>1.0.3<\/h4>\n\n<ul>\n<li>Added: <code>soderlind_aivalve_plugin_policy<\/code> filter to override allow\/deny policy programmatically.<\/li>\n<li>Added: <code>soderlind_aivalve_request_denied<\/code> action, fired when a request is blocked.<\/li>\n<li>Added: <code>soderlind_aivalve_request_completed<\/code> action, fired after every successful request.<\/li>\n<\/ul>\n\n<h4>1.0.2<\/h4>\n\n<ul>\n<li>Fixed: Resolve multiple security vulnerabilities in transitive dependencies.<\/li>\n<\/ul>\n\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Added: FAQ entry on deny-by-default allowlist setup.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Fixed: AI requests that fail (auth errors, timeouts, bad deployments) now logged with status = 'error'.<\/li>\n<li>Fixed: Schema migrations run on every load (version-gated) so in-place updates work without deactivate\/activate.<\/li>\n<li>Changed: on_before_generate inserts a pending log row immediately; on_after_generate updates it.<\/li>\n<li>Changed: Shutdown handler catches orphaned pending rows and marks them as errors.<\/li>\n<li>Added: LogRepository::update() for updating existing log rows by ID.<\/li>\n<\/ul>\n\n<h4>0.6.0<\/h4>\n\n<ul>\n<li>Added: Request duration tracking (duration_ms column, schema v3).<\/li>\n<li>Added: Log retention setting \u2014 auto-delete logs older than N days via daily cron.<\/li>\n<li>Added: Purge all logs REST endpoint (DELETE \/logs) and Danger Zone UI on Logs tab.<\/li>\n<li>Added: Time-range preset selector (24h \/ 7d \/ 30d \/ This month) on Logs tab.<\/li>\n<li>Added: Combined Provider \/ Model column in log tables with duration display.<\/li>\n<li>Added: Dropdown filters for Plugin, Provider, and Model on Logs tab (GET \/logs\/filters).<\/li>\n<li>Changed: Database schema upgraded to v3.<\/li>\n<li>Changed: Moved Danger Zone (purge) from Settings to Logs tab.<\/li>\n<\/ul>\n\n<h4>0.5.0<\/h4>\n\n<ul>\n<li>Removed: Reflection-based event dispatcher injection workaround (fixed in WP 7 RC1).<\/li>\n<li>Changed: Tested up to WP 7.0-RC1.<\/li>\n<\/ul>\n\n<h4>0.4.0<\/h4>\n\n<ul>\n<li>Changed: Admin UI rebuilt as a React single-page application.<\/li>\n<li>Changed: Settings, dashboard, and logs now render client-side via the REST API.<\/li>\n<li>Added: REST endpoint <code>GET \/settings<\/code> for reading all plugin settings.<\/li>\n<li>Added: <code>by_context<\/code>, <code>recent<\/code>, and <code>known_slugs<\/code> fields in the <code>GET \/usage<\/code> response.<\/li>\n<li>Added: <code>date_from<\/code> and <code>date_to<\/code> filter parameters on the <code>GET \/logs<\/code> endpoint.<\/li>\n<li>Added: Dedicated CSS file for admin styles (replaces inline styles).<\/li>\n<\/ul>\n\n<h4>0.3.0<\/h4>\n\n<ul>\n<li>Added: Model filter on the Logs tab and CSV export.<\/li>\n<li>Added: Provider &amp; Model breakdown table on the Dashboard.<\/li>\n<li>Added: Per-plugin token bar chart on the Dashboard.<\/li>\n<li>Added: Per-provider token counters.<\/li>\n<li>Changed: Providers &amp; Contexts tables displayed side by side.<\/li>\n<li>Changed: Plugin list only shows plugins that used the AI connector.<\/li>\n<\/ul>\n\n<h4>0.2.0<\/h4>\n\n<ul>\n<li>Fixed: Status column widened \u2014 denial reasons were silently truncated.<\/li>\n<li>Fixed: \"Denied\" log filter now matches all denial variants.<\/li>\n<li>Fixed: Respect the <code>wp_supports_ai<\/code> filter as a global kill switch.<\/li>\n<li>Added: Date range filter (From \/ To) on the Logs tab.<\/li>\n<li>Added: Context breakdown table on the Dashboard tab.<\/li>\n<li>Added: Per-plugin budget threshold alerts (admin notices).<\/li>\n<li>Added: CSV export button on the Logs tab.<\/li>\n<li>Changed: Logs filter bar uses flex layout for better fit.<\/li>\n<\/ul>\n\n<h4>0.1.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<li>Per-plugin access control (allow\/deny).<\/li>\n<li>Global and per-plugin daily\/monthly token budgets.<\/li>\n<li>Context restrictions (admin, frontend, cron, REST, AJAX, CLI).<\/li>\n<li>Usage dashboard with summary cards and progress bars.<\/li>\n<li>Request logging with provider, model, capability, and token counts.<\/li>\n<li>Budget alert notices and optional email notifications.<\/li>\n<li>REST API endpoints for usage and log data.<\/li>\n<li>Workaround for WordPress 7.0 event dispatcher bug.<\/li>\n<\/ul>","raw_excerpt":"Control, meter, and permission-gate AI usage from plugins that connect through the WordPress 7 AI connector.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/310703","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=310703"}],"author":[{"embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/pers"}],"wp:attachment":[{"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=310703"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=310703"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=310703"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=310703"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=310703"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=310703"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}