[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-automattic-create-vip-workflows-tool":3,"mdc--yur9qg-key":35,"related-repo-automattic-create-vip-workflows-tool":2773,"related-org-automattic-create-vip-workflows-tool":2813},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":22,"repoUrl":23,"updatedAt":24,"license":25,"forks":26,"topics":27,"repo":30,"sourceUrl":33,"mdContent":34},"create-vip-workflows-tool","scaffold VIP Workflows editorial tools","Scaffold a VIP Workflows editorial tool plugin. Use when the user wants to create a custom content analysis tool, validator, or checker for VIP Workflows.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"automattic","Automattic","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fautomattic.png",[12,16,19],{"name":13,"slug":14,"type":15},"WordPress","wordpress","tag",{"name":17,"slug":18,"type":15},"Plugin Development","plugin-development",{"name":20,"slug":21,"type":15},"Code Analysis","code-analysis",150,"https:\u002F\u002Fgithub.com\u002FAutomattic\u002Fvip-go-mu-plugins-built","2026-09-04T08:00:44.370747",null,38,[28,29,14],"vip","vip-go",{"repoUrl":23,"stars":22,"forks":26,"topics":31,"description":32},[28,29,14],"The generated repo for mu-plugins used on the WPVIP platform.","https:\u002F\u002Fgithub.com\u002FAutomattic\u002Fvip-go-mu-plugins-built\u002Ftree\u002FHEAD\u002Fvip-integrations\u002Fvip-workflows-0.0\u002Fskills\u002Fcreate-tool","---\nname: create-vip-workflows-tool\ndescription: >-\n  Scaffold a VIP Workflows editorial tool plugin. Use when the user wants to\n  create a custom content analysis tool, validator, or checker for VIP Workflows.\n---\n# Create a VIP Workflows Editorial Tool\n\nEditorial tools run against post content during workflow transitions or on demand from the editor sidebar. Each tool is a standalone WordPress plugin that registers an ability with the Abilities API.\n\n## Requirements\n\nBefore starting, gather from the user:\n1. **What does the tool check?** -- e.g., readability, brand compliance, SEO, fact-checking\n2. **Plugin slug** -- e.g., `workflow-tool-readability`\n3. **Ability ID** -- namespaced, e.g., `workflow-tool-readability\u002Freadability-checker`\n4. **Does it call an external API?** -- determines settings\u002Favailability patterns\n5. **Should it run on workflow transitions?** -- determines `transition_eligible` meta\n\n## Plugin Structure\n\n```\nworkflow-tool-{name}\u002F\n  workflow-tool-{name}.php          # Main plugin file\n  includes\u002F\n    class-{name}-checker.php        # Tool logic (register + execute)\n```\n\nThe plugin directory lives alongside `vip-workflows\u002F` in the same parent directory.\n\n## Boilerplate\n\n### Main plugin file: `workflow-tool-{name}\u002Fworkflow-tool-{name}.php`\n\n```php\n\u003C?php\n\u002F**\n * Plugin Name: Workflow {Display Name}\n * Description: {What this tool does, in one sentence.}\n * Version: 1.0.0\n * Requires Plugins: vip-workflows\n * Text Domain: workflow-tool-{name}\n *\n * @package WorkflowTool{PascalName}\n *\u002F\n\ndeclare( strict_types=1 );\n\nnamespace WorkflowTool{PascalName};\n\nif ( ! defined( 'ABSPATH' ) ) {\n    exit;\n}\n\nrequire_once __DIR__ . '\u002Fincludes\u002Fclass-{name}-checker.php';\n\nadd_action( 'wp_abilities_api_init', array( {PascalName}Checker::class, 'register' ) );\n```\n\n### Checker class: `workflow-tool-{name}\u002Fincludes\u002Fclass-{name}-checker.php`\n\n```php\n\u003C?php\ndeclare( strict_types=1 );\n\nnamespace WorkflowTool{PascalName};\n\nclass {PascalName}Checker {\n\n    public static function register(): void {\n        if ( ! function_exists( 'vip_workflows_register_ability' ) ) {\n            return;\n        }\n\n        vip_workflows_register_ability(\n            'workflow-tool-{name}\u002F{slug}',\n            array(\n                'label'               => __( '{Display Name}', 'workflow-tool-{name}' ),\n                'description'         => __( '{One-line description.}', 'workflow-tool-{name}' ),\n                'category'            => 'vip-workflows',\n                'input_schema'        => self::get_input_schema(),\n                'output_schema'       => self::get_output_schema(),\n                'execute_callback'    => array( self::class, 'execute' ),\n                'permission_callback' => array( self::class, 'can_execute' ),\n                'meta'                => array(\n                    'show_in_rest'        => true,\n                    'icon'                => 'search',\n                    'type'                => 'validator',\n                    'supports'            => array( 'workflow' ),\n                    'transition_eligible' => true,   \u002F\u002F expose \"Can be used in transitions\" admin toggle\n                    'show_in_commands'    => false,  \u002F\u002F set true to expose \"Show in Command Palette\" admin toggle\n                    'settings_schema'     => array(\n                        'threshold' => array(\n                            'type'        => 'integer',\n                            'default'     => 80,\n                            'label'       => 'Score threshold',\n                            'description' => 'Minimum score to pass.',\n                            'minimum'     => 0,\n                            'maximum'     => 100,\n                            'enforceable' => true, \u002F\u002F shows soft\u002Fhard check mode pill\n                        ),\n                        \u002F\u002F 'api_key' => array(\n                        \u002F\u002F     'type'     => 'string',\n                        \u002F\u002F     'label'    => 'API Key',\n                        \u002F\u002F     'required' => true,\n                        \u002F\u002F     'secret'   => true,\n                        \u002F\u002F ),\n                    ),\n                    'annotations'         => array(\n                        'readonly'    => true,\n                        'destructive' => false,\n                        'idempotent'  => true,\n                    ),\n                    \u002F\u002F See \"Availability\" below for the callback body.\n                    \u002F\u002F 'availability_callback' => array( self::class, 'check_availability' ),\n                ),\n            )\n        );\n    }\n\n    public static function can_execute(): bool {\n        return current_user_can( 'edit_posts' );\n    }\n\n    private static function get_input_schema(): array {\n        return array(\n            'type'       => 'object',\n            'properties' => array(\n                'post_id' => array( 'type' => 'integer' ),\n            ),\n            'required'   => array( 'post_id' ),\n        );\n    }\n\n    private static function get_output_schema(): array {\n        return array(\n            'type'       => 'object',\n            'properties' => array(\n                'score'   => array( 'type' => 'number' ),\n                'summary' => array( 'type' => 'string' ),\n                'issues'  => array( 'type' => 'array' ),\n            ),\n        );\n    }\n\n    \u002F**\n     * Execute the tool against a post.\n     *\n     * @param array $input { post_id: int }\n     * @return array { score: float, summary: string, issues: array }\n     *\u002F\n    public static function execute( array $input ): array {\n        $post_id = $input['post_id'] ?? 0;\n        $post    = get_post( $post_id );\n\n        if ( ! $post ) {\n            return array(\n                'score'   => 0,\n                'summary' => 'Post not found.',\n                'issues'  => array(),\n            );\n        }\n\n        \u002F\u002F Read saved settings from AbilitySettings (not from $input).\n        $settings  = \\VIPWorkflows\\Abilities\\AbilitySettings::get_instance()\n            ->get_options( 'workflow-tool-{name}\u002F{slug}' );\n        $threshold = $settings['threshold'] ?? 80;\n\n        $content = wp_strip_all_tags( $post->post_content );\n\n        $issues = self::analyze( $content );\n\n        $score = empty( $issues ) ? 100 : max( 0, 100 - ( count( $issues ) * 10 ) );\n\n        return array(\n            'score'   => $score,\n            'summary' => empty( $issues )\n                ? 'All checks passed.'\n                : sprintf( 'Found %d issues.', count( $issues ) ),\n            'issues'  => $issues,\n        );\n    }\n\n    \u002F**\n     * Analyze content and return issues.\n     *\n     * @param string $content Plain text content.\n     * @return array Array of issue arrays with 'rule', 'message', 'severity'.\n     *\u002F\n    private static function analyze( string $content ): array {\n        $issues = array();\n\n        \u002F\u002F Replace with your actual checks. Example:\n        \u002F\u002F if ( str_word_count( $content ) \u003C 300 ) {\n        \u002F\u002F     $issues[] = array(\n        \u002F\u002F         'rule'     => 'minimum-length',\n        \u002F\u002F         'message'  => 'Content is below the minimum word count of 300.',\n        \u002F\u002F         'severity' => 'warning',\n        \u002F\u002F     );\n        \u002F\u002F }\n\n        return $issues;\n    }\n}\n```\n\n## Availability\n\nA tool that needs configuration -- an API key, an external service, a plugin that may not be installed -- declares `meta.availability_callback`. `AbilityExecutor` gates execution on it, and the Tools page shows the result.\n\nWrite it against the structured shape from the start. Returning a bare `false` still works and is still silent, but it discards the reason: the surface can then only say that *something* is unconfigured, naming nothing and linking nowhere.\n\n```php\nuse VIPWorkflows\\Abilities\\Availability;\nuse VIPWorkflows\\Abilities\\RequirementFactory;\nuse VIPWorkflows\\Abilities\\RequirementGroup;\n\n\u002F**\n * Whether this tool's dependencies are met, and what is missing if not.\n *\n * @return bool|Availability True when configured, otherwise the unmet requirements.\n *\u002F\npublic static function check_availability(): bool|Availability {\n    $settings = \\VIPWorkflows\\Abilities\\AbilitySettings::get_instance();\n    $options  = $settings->get_options( 'workflow-tool-{name}\u002F{slug}' );\n\n    if ( ! empty( $options['api_key'] ) ) {\n        return true;\n    }\n\n    return Availability::unmet(\n        RequirementGroup::all(\n            RequirementFactory::in_card(\n                'settings:workflow-tool-{name}',\n                __( '{Display Name} has no API key. Add it in the tool settings below.', 'workflow-tool-{name}' ),\n                __( '{Display Name} is not connected. Ask an administrator to connect it.', 'workflow-tool-{name}' ),\n                __( 'Complete the API key field below.', 'workflow-tool-{name}' ),\n                array( __( '{Display Name}', 'workflow-tool-{name}' ) )\n            )\n        )\n    );\n}\n```\n\nRules:\n\n- **The callback owns satisfaction.** Return `true` as soon as the dependencies are met; an `Availability::unmet()` carries *only* unmet requirements, and nothing downstream re-evaluates them.\n- **A tool that generates text with AI does not write its own check.** Generate through `VIPWorkflows\\AI\\AiInference::get_instance()->model()`, never by naming a provider class, and gate with `VIPWorkflows\\Abilities\\AiAvailability::for_selected_provider( $sources )`. That pair is the whole contract: the check resolves exactly the three conditions the resolver needs — the selected provider registered with the WordPress AI Client, its credential, and a chosen model — so the gate and the generation call cannot disagree. Naming a provider yourself is how a Claude-configured site ends up being told to go get an OpenAI key. `for_provider( $provider, $sources )` exists for the rare tool that genuinely requires one specific vendor. Do not call `AiClient::isConfigured()` in an availability callback — it makes a live request, and availability is read on every Tools-page load.\n- **`AiInference::model()` returns null when the selection is unresolvable.** There is no fallback to another vendor. Bail with a `WP_Error` rather than passing null to `usingModel()`.\n- **Build requirements with `RequirementFactory`,** not by hand. Use `in_card()` when the value is entered in the tool's own `settings_schema` fields; `missing_credential( $service, $service_label, $sources )` when the key is one the plugin reads through `VIPWorkflows\\AI\\Credentials`, which resolves the destination against the install instead of hardcoding a screen; `dependency()` when a prerequisite other than a credential is missing (e.g. a required plugin is not installed); `unsupported_environment()` when nothing can be configured to fix it.\n- **Supply both message registers.** The admin reason may name a screen; the user message must not, because tools execute under `edit_posts` while admin settings require `manage_options`. The register is chosen where the requirement is read, not where it is authored.\n- Group with `RequirementGroup::all()`, or `RequirementGroup::any()` when satisfying one member is enough -- an `any` group renders as one \"configure at least one of\" block.\n- Returning `false` remains valid for a tool with nothing useful to say. It produces the generic line, with no diagnostic.\n\n## Registration Rules\n\n- The ability name **must** be namespaced with a slash: `plugin-slug\u002Fability-slug`. Never use `sanitize_key()` on ability IDs (it strips slashes).\n- `category` must be `'vip-workflows'`\n- **`meta.type` is required** for the tool to appear in Integrations > Tools. Use `'check'` for validation tools, `'helper'` for content generators, `'validator'` for analysis tools, `'agent'` for AI Agent.\n- `meta.transition_eligible = true` if the tool should run during workflow or phase transitions\n- `meta.show_in_commands = true` to expose the \"Show in Command Palette (⌘K)\" toggle in Integrations > Tools; admins control the actual value per-site. Omit or set `false` for tools that should never appear in the palette.\n- Hook into `wp_abilities_api_init`\n- Guard with `function_exists( 'vip_workflows_register_ability' )`\n- For **phase transition tools** (ideation to pitch\u002Feditorial): the input receives `project_id` (not `post_id`). Do not use `current_user_can( 'edit_post', ... )` in `permission_callback` because ideation CPTs use custom capabilities. Validate input and return `true`.\n\n## Output Contract\n\n**Declare what your tool returns.** Set `meta.result_type` to one of three values.\nThe result modal switches on that declaration rather than inspecting your output\nkeys, so a shape it has never seen still renders correctly.\n\nDo not skip this. Before `result_type` existed the modal guessed by probing keys\nin priority order, and every new shape either matched no key and rendered an empty\nmodal or matched the wrong key and applied the wrong value to a field. A tool that\ndeclares nothing still falls back to that guessing.\n\n### `result_type => 'report'` — a verdict with findings\n\nFor checks. Also the shape a transition gate reads.\n\n- `status` (string) -- `'pass'`, `'warning'` or `'fail'`. **Always set it.** Omitting\n  it means \"no verdict\", which is not the same as failing.\n- `score` (number, 0-100) -- optional\n- `summary` (string) -- one line about the result\n- `issues` (array) -- each issue has `rule`, `message`, `severity` (`'error'`, `'warning'`, `'info'`)\n\n### `result_type => 'value'` — one value that replaces a field\n\nFor generators: an excerpt, a rewritten paragraph.\n\n- `excerpt` or `content` (string) -- the value itself\n- `summary` (string) -- optional\n\nPair it with `meta.apply_field` naming the field the value belongs in, or the\nwriter gets no way to use it.\n\n### `result_type => 'list'` — several options to choose from\n\nFor suggestions: alternative headlines, related links.\n\n- `suggestions` (array) -- one of two row shapes:\n  - a **plain string**, when the row *is* a value a field can be set to (an\n    alternative headline)\n  - `array( 'label' => …, 'meta' => …, 'href' => … )`, when the row points\n    somewhere instead (a suggested link, whose label is anchor text)\n- `summary` (string) -- one line above the list\n\nOnly plain-string rows get an apply action, because only they are a value. Set\n`apply_field` for those.\n\n### `summary` is never a value\n\nIt is the line *about* a result. It is displayed, never applied. A tool that\nreturned `'5 suggested headlines.'` as its summary once had that written into a\npost title, because the modal treated the summary as content to apply.\n\n## Testing\n\n1. Place the plugin directory alongside `vip-workflows\u002F`\n2. Activate it in WordPress admin\n3. Go to Integrations > Tools to verify it appears\n4. Open a post in the editor; the tool should appear in the sidebar\n",{"data":36,"body":37},{"name":4,"description":6},{"type":38,"children":39},"root",[40,49,55,62,67,144,150,162,175,181,194,400,412,1650,1656,1677,1698,1928,1933,2177,2183,2380,2386,2404,2417,2429,2434,2554,2566,2571,2602,2615,2627,2632,2689,2702,2713,2733,2739,2767],{"type":41,"tag":42,"props":43,"children":45},"element","h1",{"id":44},"create-a-vip-workflows-editorial-tool",[46],{"type":47,"value":48},"text","Create a VIP Workflows Editorial Tool",{"type":41,"tag":50,"props":51,"children":52},"p",{},[53],{"type":47,"value":54},"Editorial tools run against post content during workflow transitions or on demand from the editor sidebar. Each tool is a standalone WordPress plugin that registers an ability with the Abilities API.",{"type":41,"tag":56,"props":57,"children":59},"h2",{"id":58},"requirements",[60],{"type":47,"value":61},"Requirements",{"type":41,"tag":50,"props":63,"children":64},{},[65],{"type":47,"value":66},"Before starting, gather from the user:",{"type":41,"tag":68,"props":69,"children":70},"ol",{},[71,83,100,116,126],{"type":41,"tag":72,"props":73,"children":74},"li",{},[75,81],{"type":41,"tag":76,"props":77,"children":78},"strong",{},[79],{"type":47,"value":80},"What does the tool check?",{"type":47,"value":82}," -- e.g., readability, brand compliance, SEO, fact-checking",{"type":41,"tag":72,"props":84,"children":85},{},[86,91,93],{"type":41,"tag":76,"props":87,"children":88},{},[89],{"type":47,"value":90},"Plugin slug",{"type":47,"value":92}," -- e.g., ",{"type":41,"tag":94,"props":95,"children":97},"code",{"className":96},[],[98],{"type":47,"value":99},"workflow-tool-readability",{"type":41,"tag":72,"props":101,"children":102},{},[103,108,110],{"type":41,"tag":76,"props":104,"children":105},{},[106],{"type":47,"value":107},"Ability ID",{"type":47,"value":109}," -- namespaced, e.g., ",{"type":41,"tag":94,"props":111,"children":113},{"className":112},[],[114],{"type":47,"value":115},"workflow-tool-readability\u002Freadability-checker",{"type":41,"tag":72,"props":117,"children":118},{},[119,124],{"type":41,"tag":76,"props":120,"children":121},{},[122],{"type":47,"value":123},"Does it call an external API?",{"type":47,"value":125}," -- determines settings\u002Favailability patterns",{"type":41,"tag":72,"props":127,"children":128},{},[129,134,136,142],{"type":41,"tag":76,"props":130,"children":131},{},[132],{"type":47,"value":133},"Should it run on workflow transitions?",{"type":47,"value":135}," -- determines ",{"type":41,"tag":94,"props":137,"children":139},{"className":138},[],[140],{"type":47,"value":141},"transition_eligible",{"type":47,"value":143}," meta",{"type":41,"tag":56,"props":145,"children":147},{"id":146},"plugin-structure",[148],{"type":47,"value":149},"Plugin Structure",{"type":41,"tag":151,"props":152,"children":156},"pre",{"className":153,"code":155,"language":47},[154],"language-text","workflow-tool-{name}\u002F\n  workflow-tool-{name}.php          # Main plugin file\n  includes\u002F\n    class-{name}-checker.php        # Tool logic (register + execute)\n",[157],{"type":41,"tag":94,"props":158,"children":160},{"__ignoreMap":159},"",[161],{"type":47,"value":155},{"type":41,"tag":50,"props":163,"children":164},{},[165,167,173],{"type":47,"value":166},"The plugin directory lives alongside ",{"type":41,"tag":94,"props":168,"children":170},{"className":169},[],[171],{"type":47,"value":172},"vip-workflows\u002F",{"type":47,"value":174}," in the same parent directory.",{"type":41,"tag":56,"props":176,"children":178},{"id":177},"boilerplate",[179],{"type":47,"value":180},"Boilerplate",{"type":41,"tag":182,"props":183,"children":185},"h3",{"id":184},"main-plugin-file-workflow-tool-nameworkflow-tool-namephp",[186,188],{"type":47,"value":187},"Main plugin file: ",{"type":41,"tag":94,"props":189,"children":191},{"className":190},[],[192],{"type":47,"value":193},"workflow-tool-{name}\u002Fworkflow-tool-{name}.php",{"type":41,"tag":151,"props":195,"children":199},{"className":196,"code":197,"language":198,"meta":159,"style":159},"language-php shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003C?php\n\u002F**\n * Plugin Name: Workflow {Display Name}\n * Description: {What this tool does, in one sentence.}\n * Version: 1.0.0\n * Requires Plugins: vip-workflows\n * Text Domain: workflow-tool-{name}\n *\n * @package WorkflowTool{PascalName}\n *\u002F\n\ndeclare( strict_types=1 );\n\nnamespace WorkflowTool{PascalName};\n\nif ( ! defined( 'ABSPATH' ) ) {\n    exit;\n}\n\nrequire_once __DIR__ . '\u002Fincludes\u002Fclass-{name}-checker.php';\n\nadd_action( 'wp_abilities_api_init', array( {PascalName}Checker::class, 'register' ) );\n","php",[200],{"type":41,"tag":94,"props":201,"children":202},{"__ignoreMap":159},[203,214,223,232,241,250,259,268,277,286,295,305,314,322,331,339,348,357,366,374,383,391],{"type":41,"tag":204,"props":205,"children":208},"span",{"class":206,"line":207},"line",1,[209],{"type":41,"tag":204,"props":210,"children":211},{},[212],{"type":47,"value":213},"\u003C?php\n",{"type":41,"tag":204,"props":215,"children":217},{"class":206,"line":216},2,[218],{"type":41,"tag":204,"props":219,"children":220},{},[221],{"type":47,"value":222},"\u002F**\n",{"type":41,"tag":204,"props":224,"children":226},{"class":206,"line":225},3,[227],{"type":41,"tag":204,"props":228,"children":229},{},[230],{"type":47,"value":231}," * Plugin Name: Workflow {Display Name}\n",{"type":41,"tag":204,"props":233,"children":235},{"class":206,"line":234},4,[236],{"type":41,"tag":204,"props":237,"children":238},{},[239],{"type":47,"value":240}," * Description: {What this tool does, in one sentence.}\n",{"type":41,"tag":204,"props":242,"children":244},{"class":206,"line":243},5,[245],{"type":41,"tag":204,"props":246,"children":247},{},[248],{"type":47,"value":249}," * Version: 1.0.0\n",{"type":41,"tag":204,"props":251,"children":253},{"class":206,"line":252},6,[254],{"type":41,"tag":204,"props":255,"children":256},{},[257],{"type":47,"value":258}," * Requires Plugins: vip-workflows\n",{"type":41,"tag":204,"props":260,"children":262},{"class":206,"line":261},7,[263],{"type":41,"tag":204,"props":264,"children":265},{},[266],{"type":47,"value":267}," * Text Domain: workflow-tool-{name}\n",{"type":41,"tag":204,"props":269,"children":271},{"class":206,"line":270},8,[272],{"type":41,"tag":204,"props":273,"children":274},{},[275],{"type":47,"value":276}," *\n",{"type":41,"tag":204,"props":278,"children":280},{"class":206,"line":279},9,[281],{"type":41,"tag":204,"props":282,"children":283},{},[284],{"type":47,"value":285}," * @package WorkflowTool{PascalName}\n",{"type":41,"tag":204,"props":287,"children":289},{"class":206,"line":288},10,[290],{"type":41,"tag":204,"props":291,"children":292},{},[293],{"type":47,"value":294}," *\u002F\n",{"type":41,"tag":204,"props":296,"children":298},{"class":206,"line":297},11,[299],{"type":41,"tag":204,"props":300,"children":302},{"emptyLinePlaceholder":301},true,[303],{"type":47,"value":304},"\n",{"type":41,"tag":204,"props":306,"children":308},{"class":206,"line":307},12,[309],{"type":41,"tag":204,"props":310,"children":311},{},[312],{"type":47,"value":313},"declare( strict_types=1 );\n",{"type":41,"tag":204,"props":315,"children":317},{"class":206,"line":316},13,[318],{"type":41,"tag":204,"props":319,"children":320},{"emptyLinePlaceholder":301},[321],{"type":47,"value":304},{"type":41,"tag":204,"props":323,"children":325},{"class":206,"line":324},14,[326],{"type":41,"tag":204,"props":327,"children":328},{},[329],{"type":47,"value":330},"namespace WorkflowTool{PascalName};\n",{"type":41,"tag":204,"props":332,"children":334},{"class":206,"line":333},15,[335],{"type":41,"tag":204,"props":336,"children":337},{"emptyLinePlaceholder":301},[338],{"type":47,"value":304},{"type":41,"tag":204,"props":340,"children":342},{"class":206,"line":341},16,[343],{"type":41,"tag":204,"props":344,"children":345},{},[346],{"type":47,"value":347},"if ( ! defined( 'ABSPATH' ) ) {\n",{"type":41,"tag":204,"props":349,"children":351},{"class":206,"line":350},17,[352],{"type":41,"tag":204,"props":353,"children":354},{},[355],{"type":47,"value":356},"    exit;\n",{"type":41,"tag":204,"props":358,"children":360},{"class":206,"line":359},18,[361],{"type":41,"tag":204,"props":362,"children":363},{},[364],{"type":47,"value":365},"}\n",{"type":41,"tag":204,"props":367,"children":369},{"class":206,"line":368},19,[370],{"type":41,"tag":204,"props":371,"children":372},{"emptyLinePlaceholder":301},[373],{"type":47,"value":304},{"type":41,"tag":204,"props":375,"children":377},{"class":206,"line":376},20,[378],{"type":41,"tag":204,"props":379,"children":380},{},[381],{"type":47,"value":382},"require_once __DIR__ . '\u002Fincludes\u002Fclass-{name}-checker.php';\n",{"type":41,"tag":204,"props":384,"children":386},{"class":206,"line":385},21,[387],{"type":41,"tag":204,"props":388,"children":389},{"emptyLinePlaceholder":301},[390],{"type":47,"value":304},{"type":41,"tag":204,"props":392,"children":394},{"class":206,"line":393},22,[395],{"type":41,"tag":204,"props":396,"children":397},{},[398],{"type":47,"value":399},"add_action( 'wp_abilities_api_init', array( {PascalName}Checker::class, 'register' ) );\n",{"type":41,"tag":182,"props":401,"children":403},{"id":402},"checker-class-workflow-tool-nameincludesclass-name-checkerphp",[404,406],{"type":47,"value":405},"Checker class: ",{"type":41,"tag":94,"props":407,"children":409},{"className":408},[],[410],{"type":47,"value":411},"workflow-tool-{name}\u002Fincludes\u002Fclass-{name}-checker.php",{"type":41,"tag":151,"props":413,"children":415},{"className":196,"code":414,"language":198,"meta":159,"style":159},"\u003C?php\ndeclare( strict_types=1 );\n\nnamespace WorkflowTool{PascalName};\n\nclass {PascalName}Checker {\n\n    public static function register(): void {\n        if ( ! function_exists( 'vip_workflows_register_ability' ) ) {\n            return;\n        }\n\n        vip_workflows_register_ability(\n            'workflow-tool-{name}\u002F{slug}',\n            array(\n                'label'               => __( '{Display Name}', 'workflow-tool-{name}' ),\n                'description'         => __( '{One-line description.}', 'workflow-tool-{name}' ),\n                'category'            => 'vip-workflows',\n                'input_schema'        => self::get_input_schema(),\n                'output_schema'       => self::get_output_schema(),\n                'execute_callback'    => array( self::class, 'execute' ),\n                'permission_callback' => array( self::class, 'can_execute' ),\n                'meta'                => array(\n                    'show_in_rest'        => true,\n                    'icon'                => 'search',\n                    'type'                => 'validator',\n                    'supports'            => array( 'workflow' ),\n                    'transition_eligible' => true,   \u002F\u002F expose \"Can be used in transitions\" admin toggle\n                    'show_in_commands'    => false,  \u002F\u002F set true to expose \"Show in Command Palette\" admin toggle\n                    'settings_schema'     => array(\n                        'threshold' => array(\n                            'type'        => 'integer',\n                            'default'     => 80,\n                            'label'       => 'Score threshold',\n                            'description' => 'Minimum score to pass.',\n                            'minimum'     => 0,\n                            'maximum'     => 100,\n                            'enforceable' => true, \u002F\u002F shows soft\u002Fhard check mode pill\n                        ),\n                        \u002F\u002F 'api_key' => array(\n                        \u002F\u002F     'type'     => 'string',\n                        \u002F\u002F     'label'    => 'API Key',\n                        \u002F\u002F     'required' => true,\n                        \u002F\u002F     'secret'   => true,\n                        \u002F\u002F ),\n                    ),\n                    'annotations'         => array(\n                        'readonly'    => true,\n                        'destructive' => false,\n                        'idempotent'  => true,\n                    ),\n                    \u002F\u002F See \"Availability\" below for the callback body.\n                    \u002F\u002F 'availability_callback' => array( self::class, 'check_availability' ),\n                ),\n            )\n        );\n    }\n\n    public static function can_execute(): bool {\n        return current_user_can( 'edit_posts' );\n    }\n\n    private static function get_input_schema(): array {\n        return array(\n            'type'       => 'object',\n            'properties' => array(\n                'post_id' => array( 'type' => 'integer' ),\n            ),\n            'required'   => array( 'post_id' ),\n        );\n    }\n\n    private static function get_output_schema(): array {\n        return array(\n            'type'       => 'object',\n            'properties' => array(\n                'score'   => array( 'type' => 'number' ),\n                'summary' => array( 'type' => 'string' ),\n                'issues'  => array( 'type' => 'array' ),\n            ),\n        );\n    }\n\n    \u002F**\n     * Execute the tool against a post.\n     *\n     * @param array $input { post_id: int }\n     * @return array { score: float, summary: string, issues: array }\n     *\u002F\n    public static function execute( array $input ): array {\n        $post_id = $input['post_id'] ?? 0;\n        $post    = get_post( $post_id );\n\n        if ( ! $post ) {\n            return array(\n                'score'   => 0,\n                'summary' => 'Post not found.',\n                'issues'  => array(),\n            );\n        }\n\n        \u002F\u002F Read saved settings from AbilitySettings (not from $input).\n        $settings  = \\VIPWorkflows\\Abilities\\AbilitySettings::get_instance()\n            ->get_options( 'workflow-tool-{name}\u002F{slug}' );\n        $threshold = $settings['threshold'] ?? 80;\n\n        $content = wp_strip_all_tags( $post->post_content );\n\n        $issues = self::analyze( $content );\n\n        $score = empty( $issues ) ? 100 : max( 0, 100 - ( count( $issues ) * 10 ) );\n\n        return array(\n            'score'   => $score,\n            'summary' => empty( $issues )\n                ? 'All checks passed.'\n                : sprintf( 'Found %d issues.', count( $issues ) ),\n            'issues'  => $issues,\n        );\n    }\n\n    \u002F**\n     * Analyze content and return issues.\n     *\n     * @param string $content Plain text content.\n     * @return array Array of issue arrays with 'rule', 'message', 'severity'.\n     *\u002F\n    private static function analyze( string $content ): array {\n        $issues = array();\n\n        \u002F\u002F Replace with your actual checks. Example:\n        \u002F\u002F if ( str_word_count( $content ) \u003C 300 ) {\n        \u002F\u002F     $issues[] = array(\n        \u002F\u002F         'rule'     => 'minimum-length',\n        \u002F\u002F         'message'  => 'Content is below the minimum word count of 300.',\n        \u002F\u002F         'severity' => 'warning',\n        \u002F\u002F     );\n        \u002F\u002F }\n\n        return $issues;\n    }\n}\n",[416],{"type":41,"tag":94,"props":417,"children":418},{"__ignoreMap":159},[419,426,433,440,447,454,462,469,477,485,493,501,508,516,524,532,540,548,556,564,572,580,588,597,606,615,624,633,647,661,670,679,688,697,706,715,724,733,746,755,764,773,782,791,800,809,818,827,836,845,854,862,871,880,889,898,907,916,924,933,942,950,958,967,976,985,994,1003,1012,1021,1029,1037,1045,1054,1062,1070,1078,1087,1096,1105,1113,1121,1129,1137,1146,1155,1164,1173,1182,1191,1200,1209,1218,1226,1235,1244,1253,1262,1271,1280,1288,1296,1305,1314,1323,1332,1340,1349,1357,1366,1374,1383,1391,1399,1408,1417,1426,1435,1444,1452,1460,1468,1476,1485,1493,1502,1511,1519,1528,1537,1545,1554,1563,1572,1581,1590,1599,1608,1617,1625,1634,1642],{"type":41,"tag":204,"props":420,"children":421},{"class":206,"line":207},[422],{"type":41,"tag":204,"props":423,"children":424},{},[425],{"type":47,"value":213},{"type":41,"tag":204,"props":427,"children":428},{"class":206,"line":216},[429],{"type":41,"tag":204,"props":430,"children":431},{},[432],{"type":47,"value":313},{"type":41,"tag":204,"props":434,"children":435},{"class":206,"line":225},[436],{"type":41,"tag":204,"props":437,"children":438},{"emptyLinePlaceholder":301},[439],{"type":47,"value":304},{"type":41,"tag":204,"props":441,"children":442},{"class":206,"line":234},[443],{"type":41,"tag":204,"props":444,"children":445},{},[446],{"type":47,"value":330},{"type":41,"tag":204,"props":448,"children":449},{"class":206,"line":243},[450],{"type":41,"tag":204,"props":451,"children":452},{"emptyLinePlaceholder":301},[453],{"type":47,"value":304},{"type":41,"tag":204,"props":455,"children":456},{"class":206,"line":252},[457],{"type":41,"tag":204,"props":458,"children":459},{},[460],{"type":47,"value":461},"class {PascalName}Checker {\n",{"type":41,"tag":204,"props":463,"children":464},{"class":206,"line":261},[465],{"type":41,"tag":204,"props":466,"children":467},{"emptyLinePlaceholder":301},[468],{"type":47,"value":304},{"type":41,"tag":204,"props":470,"children":471},{"class":206,"line":270},[472],{"type":41,"tag":204,"props":473,"children":474},{},[475],{"type":47,"value":476},"    public static function register(): void {\n",{"type":41,"tag":204,"props":478,"children":479},{"class":206,"line":279},[480],{"type":41,"tag":204,"props":481,"children":482},{},[483],{"type":47,"value":484},"        if ( ! function_exists( 'vip_workflows_register_ability' ) ) {\n",{"type":41,"tag":204,"props":486,"children":487},{"class":206,"line":288},[488],{"type":41,"tag":204,"props":489,"children":490},{},[491],{"type":47,"value":492},"            return;\n",{"type":41,"tag":204,"props":494,"children":495},{"class":206,"line":297},[496],{"type":41,"tag":204,"props":497,"children":498},{},[499],{"type":47,"value":500},"        }\n",{"type":41,"tag":204,"props":502,"children":503},{"class":206,"line":307},[504],{"type":41,"tag":204,"props":505,"children":506},{"emptyLinePlaceholder":301},[507],{"type":47,"value":304},{"type":41,"tag":204,"props":509,"children":510},{"class":206,"line":316},[511],{"type":41,"tag":204,"props":512,"children":513},{},[514],{"type":47,"value":515},"        vip_workflows_register_ability(\n",{"type":41,"tag":204,"props":517,"children":518},{"class":206,"line":324},[519],{"type":41,"tag":204,"props":520,"children":521},{},[522],{"type":47,"value":523},"            'workflow-tool-{name}\u002F{slug}',\n",{"type":41,"tag":204,"props":525,"children":526},{"class":206,"line":333},[527],{"type":41,"tag":204,"props":528,"children":529},{},[530],{"type":47,"value":531},"            array(\n",{"type":41,"tag":204,"props":533,"children":534},{"class":206,"line":341},[535],{"type":41,"tag":204,"props":536,"children":537},{},[538],{"type":47,"value":539},"                'label'               => __( '{Display Name}', 'workflow-tool-{name}' ),\n",{"type":41,"tag":204,"props":541,"children":542},{"class":206,"line":350},[543],{"type":41,"tag":204,"props":544,"children":545},{},[546],{"type":47,"value":547},"                'description'         => __( '{One-line description.}', 'workflow-tool-{name}' ),\n",{"type":41,"tag":204,"props":549,"children":550},{"class":206,"line":359},[551],{"type":41,"tag":204,"props":552,"children":553},{},[554],{"type":47,"value":555},"                'category'            => 'vip-workflows',\n",{"type":41,"tag":204,"props":557,"children":558},{"class":206,"line":368},[559],{"type":41,"tag":204,"props":560,"children":561},{},[562],{"type":47,"value":563},"                'input_schema'        => self::get_input_schema(),\n",{"type":41,"tag":204,"props":565,"children":566},{"class":206,"line":376},[567],{"type":41,"tag":204,"props":568,"children":569},{},[570],{"type":47,"value":571},"                'output_schema'       => self::get_output_schema(),\n",{"type":41,"tag":204,"props":573,"children":574},{"class":206,"line":385},[575],{"type":41,"tag":204,"props":576,"children":577},{},[578],{"type":47,"value":579},"                'execute_callback'    => array( self::class, 'execute' ),\n",{"type":41,"tag":204,"props":581,"children":582},{"class":206,"line":393},[583],{"type":41,"tag":204,"props":584,"children":585},{},[586],{"type":47,"value":587},"                'permission_callback' => array( self::class, 'can_execute' ),\n",{"type":41,"tag":204,"props":589,"children":591},{"class":206,"line":590},23,[592],{"type":41,"tag":204,"props":593,"children":594},{},[595],{"type":47,"value":596},"                'meta'                => array(\n",{"type":41,"tag":204,"props":598,"children":600},{"class":206,"line":599},24,[601],{"type":41,"tag":204,"props":602,"children":603},{},[604],{"type":47,"value":605},"                    'show_in_rest'        => true,\n",{"type":41,"tag":204,"props":607,"children":609},{"class":206,"line":608},25,[610],{"type":41,"tag":204,"props":611,"children":612},{},[613],{"type":47,"value":614},"                    'icon'                => 'search',\n",{"type":41,"tag":204,"props":616,"children":618},{"class":206,"line":617},26,[619],{"type":41,"tag":204,"props":620,"children":621},{},[622],{"type":47,"value":623},"                    'type'                => 'validator',\n",{"type":41,"tag":204,"props":625,"children":627},{"class":206,"line":626},27,[628],{"type":41,"tag":204,"props":629,"children":630},{},[631],{"type":47,"value":632},"                    'supports'            => array( 'workflow' ),\n",{"type":41,"tag":204,"props":634,"children":636},{"class":206,"line":635},28,[637,642],{"type":41,"tag":204,"props":638,"children":639},{},[640],{"type":47,"value":641},"                    'transition_eligible' => true,",{"type":41,"tag":204,"props":643,"children":644},{},[645],{"type":47,"value":646},"   \u002F\u002F expose \"Can be used in transitions\" admin toggle\n",{"type":41,"tag":204,"props":648,"children":650},{"class":206,"line":649},29,[651,656],{"type":41,"tag":204,"props":652,"children":653},{},[654],{"type":47,"value":655},"                    'show_in_commands'    => false,",{"type":41,"tag":204,"props":657,"children":658},{},[659],{"type":47,"value":660},"  \u002F\u002F set true to expose \"Show in Command Palette\" admin toggle\n",{"type":41,"tag":204,"props":662,"children":664},{"class":206,"line":663},30,[665],{"type":41,"tag":204,"props":666,"children":667},{},[668],{"type":47,"value":669},"                    'settings_schema'     => array(\n",{"type":41,"tag":204,"props":671,"children":673},{"class":206,"line":672},31,[674],{"type":41,"tag":204,"props":675,"children":676},{},[677],{"type":47,"value":678},"                        'threshold' => array(\n",{"type":41,"tag":204,"props":680,"children":682},{"class":206,"line":681},32,[683],{"type":41,"tag":204,"props":684,"children":685},{},[686],{"type":47,"value":687},"                            'type'        => 'integer',\n",{"type":41,"tag":204,"props":689,"children":691},{"class":206,"line":690},33,[692],{"type":41,"tag":204,"props":693,"children":694},{},[695],{"type":47,"value":696},"                            'default'     => 80,\n",{"type":41,"tag":204,"props":698,"children":700},{"class":206,"line":699},34,[701],{"type":41,"tag":204,"props":702,"children":703},{},[704],{"type":47,"value":705},"                            'label'       => 'Score threshold',\n",{"type":41,"tag":204,"props":707,"children":709},{"class":206,"line":708},35,[710],{"type":41,"tag":204,"props":711,"children":712},{},[713],{"type":47,"value":714},"                            'description' => 'Minimum score to pass.',\n",{"type":41,"tag":204,"props":716,"children":718},{"class":206,"line":717},36,[719],{"type":41,"tag":204,"props":720,"children":721},{},[722],{"type":47,"value":723},"                            'minimum'     => 0,\n",{"type":41,"tag":204,"props":725,"children":727},{"class":206,"line":726},37,[728],{"type":41,"tag":204,"props":729,"children":730},{},[731],{"type":47,"value":732},"                            'maximum'     => 100,\n",{"type":41,"tag":204,"props":734,"children":735},{"class":206,"line":26},[736,741],{"type":41,"tag":204,"props":737,"children":738},{},[739],{"type":47,"value":740},"                            'enforceable' => true,",{"type":41,"tag":204,"props":742,"children":743},{},[744],{"type":47,"value":745}," \u002F\u002F shows soft\u002Fhard check mode pill\n",{"type":41,"tag":204,"props":747,"children":749},{"class":206,"line":748},39,[750],{"type":41,"tag":204,"props":751,"children":752},{},[753],{"type":47,"value":754},"                        ),\n",{"type":41,"tag":204,"props":756,"children":758},{"class":206,"line":757},40,[759],{"type":41,"tag":204,"props":760,"children":761},{},[762],{"type":47,"value":763},"                        \u002F\u002F 'api_key' => array(\n",{"type":41,"tag":204,"props":765,"children":767},{"class":206,"line":766},41,[768],{"type":41,"tag":204,"props":769,"children":770},{},[771],{"type":47,"value":772},"                        \u002F\u002F     'type'     => 'string',\n",{"type":41,"tag":204,"props":774,"children":776},{"class":206,"line":775},42,[777],{"type":41,"tag":204,"props":778,"children":779},{},[780],{"type":47,"value":781},"                        \u002F\u002F     'label'    => 'API Key',\n",{"type":41,"tag":204,"props":783,"children":785},{"class":206,"line":784},43,[786],{"type":41,"tag":204,"props":787,"children":788},{},[789],{"type":47,"value":790},"                        \u002F\u002F     'required' => true,\n",{"type":41,"tag":204,"props":792,"children":794},{"class":206,"line":793},44,[795],{"type":41,"tag":204,"props":796,"children":797},{},[798],{"type":47,"value":799},"                        \u002F\u002F     'secret'   => true,\n",{"type":41,"tag":204,"props":801,"children":803},{"class":206,"line":802},45,[804],{"type":41,"tag":204,"props":805,"children":806},{},[807],{"type":47,"value":808},"                        \u002F\u002F ),\n",{"type":41,"tag":204,"props":810,"children":812},{"class":206,"line":811},46,[813],{"type":41,"tag":204,"props":814,"children":815},{},[816],{"type":47,"value":817},"                    ),\n",{"type":41,"tag":204,"props":819,"children":821},{"class":206,"line":820},47,[822],{"type":41,"tag":204,"props":823,"children":824},{},[825],{"type":47,"value":826},"                    'annotations'         => array(\n",{"type":41,"tag":204,"props":828,"children":830},{"class":206,"line":829},48,[831],{"type":41,"tag":204,"props":832,"children":833},{},[834],{"type":47,"value":835},"                        'readonly'    => true,\n",{"type":41,"tag":204,"props":837,"children":839},{"class":206,"line":838},49,[840],{"type":41,"tag":204,"props":841,"children":842},{},[843],{"type":47,"value":844},"                        'destructive' => false,\n",{"type":41,"tag":204,"props":846,"children":848},{"class":206,"line":847},50,[849],{"type":41,"tag":204,"props":850,"children":851},{},[852],{"type":47,"value":853},"                        'idempotent'  => true,\n",{"type":41,"tag":204,"props":855,"children":857},{"class":206,"line":856},51,[858],{"type":41,"tag":204,"props":859,"children":860},{},[861],{"type":47,"value":817},{"type":41,"tag":204,"props":863,"children":865},{"class":206,"line":864},52,[866],{"type":41,"tag":204,"props":867,"children":868},{},[869],{"type":47,"value":870},"                    \u002F\u002F See \"Availability\" below for the callback body.\n",{"type":41,"tag":204,"props":872,"children":874},{"class":206,"line":873},53,[875],{"type":41,"tag":204,"props":876,"children":877},{},[878],{"type":47,"value":879},"                    \u002F\u002F 'availability_callback' => array( self::class, 'check_availability' ),\n",{"type":41,"tag":204,"props":881,"children":883},{"class":206,"line":882},54,[884],{"type":41,"tag":204,"props":885,"children":886},{},[887],{"type":47,"value":888},"                ),\n",{"type":41,"tag":204,"props":890,"children":892},{"class":206,"line":891},55,[893],{"type":41,"tag":204,"props":894,"children":895},{},[896],{"type":47,"value":897},"            )\n",{"type":41,"tag":204,"props":899,"children":901},{"class":206,"line":900},56,[902],{"type":41,"tag":204,"props":903,"children":904},{},[905],{"type":47,"value":906},"        );\n",{"type":41,"tag":204,"props":908,"children":910},{"class":206,"line":909},57,[911],{"type":41,"tag":204,"props":912,"children":913},{},[914],{"type":47,"value":915},"    }\n",{"type":41,"tag":204,"props":917,"children":919},{"class":206,"line":918},58,[920],{"type":41,"tag":204,"props":921,"children":922},{"emptyLinePlaceholder":301},[923],{"type":47,"value":304},{"type":41,"tag":204,"props":925,"children":927},{"class":206,"line":926},59,[928],{"type":41,"tag":204,"props":929,"children":930},{},[931],{"type":47,"value":932},"    public static function can_execute(): bool {\n",{"type":41,"tag":204,"props":934,"children":936},{"class":206,"line":935},60,[937],{"type":41,"tag":204,"props":938,"children":939},{},[940],{"type":47,"value":941},"        return current_user_can( 'edit_posts' );\n",{"type":41,"tag":204,"props":943,"children":945},{"class":206,"line":944},61,[946],{"type":41,"tag":204,"props":947,"children":948},{},[949],{"type":47,"value":915},{"type":41,"tag":204,"props":951,"children":953},{"class":206,"line":952},62,[954],{"type":41,"tag":204,"props":955,"children":956},{"emptyLinePlaceholder":301},[957],{"type":47,"value":304},{"type":41,"tag":204,"props":959,"children":961},{"class":206,"line":960},63,[962],{"type":41,"tag":204,"props":963,"children":964},{},[965],{"type":47,"value":966},"    private static function get_input_schema(): array {\n",{"type":41,"tag":204,"props":968,"children":970},{"class":206,"line":969},64,[971],{"type":41,"tag":204,"props":972,"children":973},{},[974],{"type":47,"value":975},"        return array(\n",{"type":41,"tag":204,"props":977,"children":979},{"class":206,"line":978},65,[980],{"type":41,"tag":204,"props":981,"children":982},{},[983],{"type":47,"value":984},"            'type'       => 'object',\n",{"type":41,"tag":204,"props":986,"children":988},{"class":206,"line":987},66,[989],{"type":41,"tag":204,"props":990,"children":991},{},[992],{"type":47,"value":993},"            'properties' => array(\n",{"type":41,"tag":204,"props":995,"children":997},{"class":206,"line":996},67,[998],{"type":41,"tag":204,"props":999,"children":1000},{},[1001],{"type":47,"value":1002},"                'post_id' => array( 'type' => 'integer' ),\n",{"type":41,"tag":204,"props":1004,"children":1006},{"class":206,"line":1005},68,[1007],{"type":41,"tag":204,"props":1008,"children":1009},{},[1010],{"type":47,"value":1011},"            ),\n",{"type":41,"tag":204,"props":1013,"children":1015},{"class":206,"line":1014},69,[1016],{"type":41,"tag":204,"props":1017,"children":1018},{},[1019],{"type":47,"value":1020},"            'required'   => array( 'post_id' ),\n",{"type":41,"tag":204,"props":1022,"children":1024},{"class":206,"line":1023},70,[1025],{"type":41,"tag":204,"props":1026,"children":1027},{},[1028],{"type":47,"value":906},{"type":41,"tag":204,"props":1030,"children":1032},{"class":206,"line":1031},71,[1033],{"type":41,"tag":204,"props":1034,"children":1035},{},[1036],{"type":47,"value":915},{"type":41,"tag":204,"props":1038,"children":1040},{"class":206,"line":1039},72,[1041],{"type":41,"tag":204,"props":1042,"children":1043},{"emptyLinePlaceholder":301},[1044],{"type":47,"value":304},{"type":41,"tag":204,"props":1046,"children":1048},{"class":206,"line":1047},73,[1049],{"type":41,"tag":204,"props":1050,"children":1051},{},[1052],{"type":47,"value":1053},"    private static function get_output_schema(): array {\n",{"type":41,"tag":204,"props":1055,"children":1057},{"class":206,"line":1056},74,[1058],{"type":41,"tag":204,"props":1059,"children":1060},{},[1061],{"type":47,"value":975},{"type":41,"tag":204,"props":1063,"children":1065},{"class":206,"line":1064},75,[1066],{"type":41,"tag":204,"props":1067,"children":1068},{},[1069],{"type":47,"value":984},{"type":41,"tag":204,"props":1071,"children":1073},{"class":206,"line":1072},76,[1074],{"type":41,"tag":204,"props":1075,"children":1076},{},[1077],{"type":47,"value":993},{"type":41,"tag":204,"props":1079,"children":1081},{"class":206,"line":1080},77,[1082],{"type":41,"tag":204,"props":1083,"children":1084},{},[1085],{"type":47,"value":1086},"                'score'   => array( 'type' => 'number' ),\n",{"type":41,"tag":204,"props":1088,"children":1090},{"class":206,"line":1089},78,[1091],{"type":41,"tag":204,"props":1092,"children":1093},{},[1094],{"type":47,"value":1095},"                'summary' => array( 'type' => 'string' ),\n",{"type":41,"tag":204,"props":1097,"children":1099},{"class":206,"line":1098},79,[1100],{"type":41,"tag":204,"props":1101,"children":1102},{},[1103],{"type":47,"value":1104},"                'issues'  => array( 'type' => 'array' ),\n",{"type":41,"tag":204,"props":1106,"children":1108},{"class":206,"line":1107},80,[1109],{"type":41,"tag":204,"props":1110,"children":1111},{},[1112],{"type":47,"value":1011},{"type":41,"tag":204,"props":1114,"children":1116},{"class":206,"line":1115},81,[1117],{"type":41,"tag":204,"props":1118,"children":1119},{},[1120],{"type":47,"value":906},{"type":41,"tag":204,"props":1122,"children":1124},{"class":206,"line":1123},82,[1125],{"type":41,"tag":204,"props":1126,"children":1127},{},[1128],{"type":47,"value":915},{"type":41,"tag":204,"props":1130,"children":1132},{"class":206,"line":1131},83,[1133],{"type":41,"tag":204,"props":1134,"children":1135},{"emptyLinePlaceholder":301},[1136],{"type":47,"value":304},{"type":41,"tag":204,"props":1138,"children":1140},{"class":206,"line":1139},84,[1141],{"type":41,"tag":204,"props":1142,"children":1143},{},[1144],{"type":47,"value":1145},"    \u002F**\n",{"type":41,"tag":204,"props":1147,"children":1149},{"class":206,"line":1148},85,[1150],{"type":41,"tag":204,"props":1151,"children":1152},{},[1153],{"type":47,"value":1154},"     * Execute the tool against a post.\n",{"type":41,"tag":204,"props":1156,"children":1158},{"class":206,"line":1157},86,[1159],{"type":41,"tag":204,"props":1160,"children":1161},{},[1162],{"type":47,"value":1163},"     *\n",{"type":41,"tag":204,"props":1165,"children":1167},{"class":206,"line":1166},87,[1168],{"type":41,"tag":204,"props":1169,"children":1170},{},[1171],{"type":47,"value":1172},"     * @param array $input { post_id: int }\n",{"type":41,"tag":204,"props":1174,"children":1176},{"class":206,"line":1175},88,[1177],{"type":41,"tag":204,"props":1178,"children":1179},{},[1180],{"type":47,"value":1181},"     * @return array { score: float, summary: string, issues: array }\n",{"type":41,"tag":204,"props":1183,"children":1185},{"class":206,"line":1184},89,[1186],{"type":41,"tag":204,"props":1187,"children":1188},{},[1189],{"type":47,"value":1190},"     *\u002F\n",{"type":41,"tag":204,"props":1192,"children":1194},{"class":206,"line":1193},90,[1195],{"type":41,"tag":204,"props":1196,"children":1197},{},[1198],{"type":47,"value":1199},"    public static function execute( array $input ): array {\n",{"type":41,"tag":204,"props":1201,"children":1203},{"class":206,"line":1202},91,[1204],{"type":41,"tag":204,"props":1205,"children":1206},{},[1207],{"type":47,"value":1208},"        $post_id = $input['post_id'] ?? 0;\n",{"type":41,"tag":204,"props":1210,"children":1212},{"class":206,"line":1211},92,[1213],{"type":41,"tag":204,"props":1214,"children":1215},{},[1216],{"type":47,"value":1217},"        $post    = get_post( $post_id );\n",{"type":41,"tag":204,"props":1219,"children":1221},{"class":206,"line":1220},93,[1222],{"type":41,"tag":204,"props":1223,"children":1224},{"emptyLinePlaceholder":301},[1225],{"type":47,"value":304},{"type":41,"tag":204,"props":1227,"children":1229},{"class":206,"line":1228},94,[1230],{"type":41,"tag":204,"props":1231,"children":1232},{},[1233],{"type":47,"value":1234},"        if ( ! $post ) {\n",{"type":41,"tag":204,"props":1236,"children":1238},{"class":206,"line":1237},95,[1239],{"type":41,"tag":204,"props":1240,"children":1241},{},[1242],{"type":47,"value":1243},"            return array(\n",{"type":41,"tag":204,"props":1245,"children":1247},{"class":206,"line":1246},96,[1248],{"type":41,"tag":204,"props":1249,"children":1250},{},[1251],{"type":47,"value":1252},"                'score'   => 0,\n",{"type":41,"tag":204,"props":1254,"children":1256},{"class":206,"line":1255},97,[1257],{"type":41,"tag":204,"props":1258,"children":1259},{},[1260],{"type":47,"value":1261},"                'summary' => 'Post not found.',\n",{"type":41,"tag":204,"props":1263,"children":1265},{"class":206,"line":1264},98,[1266],{"type":41,"tag":204,"props":1267,"children":1268},{},[1269],{"type":47,"value":1270},"                'issues'  => array(),\n",{"type":41,"tag":204,"props":1272,"children":1274},{"class":206,"line":1273},99,[1275],{"type":41,"tag":204,"props":1276,"children":1277},{},[1278],{"type":47,"value":1279},"            );\n",{"type":41,"tag":204,"props":1281,"children":1283},{"class":206,"line":1282},100,[1284],{"type":41,"tag":204,"props":1285,"children":1286},{},[1287],{"type":47,"value":500},{"type":41,"tag":204,"props":1289,"children":1291},{"class":206,"line":1290},101,[1292],{"type":41,"tag":204,"props":1293,"children":1294},{"emptyLinePlaceholder":301},[1295],{"type":47,"value":304},{"type":41,"tag":204,"props":1297,"children":1299},{"class":206,"line":1298},102,[1300],{"type":41,"tag":204,"props":1301,"children":1302},{},[1303],{"type":47,"value":1304},"        \u002F\u002F Read saved settings from AbilitySettings (not from $input).\n",{"type":41,"tag":204,"props":1306,"children":1308},{"class":206,"line":1307},103,[1309],{"type":41,"tag":204,"props":1310,"children":1311},{},[1312],{"type":47,"value":1313},"        $settings  = \\VIPWorkflows\\Abilities\\AbilitySettings::get_instance()\n",{"type":41,"tag":204,"props":1315,"children":1317},{"class":206,"line":1316},104,[1318],{"type":41,"tag":204,"props":1319,"children":1320},{},[1321],{"type":47,"value":1322},"            ->get_options( 'workflow-tool-{name}\u002F{slug}' );\n",{"type":41,"tag":204,"props":1324,"children":1326},{"class":206,"line":1325},105,[1327],{"type":41,"tag":204,"props":1328,"children":1329},{},[1330],{"type":47,"value":1331},"        $threshold = $settings['threshold'] ?? 80;\n",{"type":41,"tag":204,"props":1333,"children":1335},{"class":206,"line":1334},106,[1336],{"type":41,"tag":204,"props":1337,"children":1338},{"emptyLinePlaceholder":301},[1339],{"type":47,"value":304},{"type":41,"tag":204,"props":1341,"children":1343},{"class":206,"line":1342},107,[1344],{"type":41,"tag":204,"props":1345,"children":1346},{},[1347],{"type":47,"value":1348},"        $content = wp_strip_all_tags( $post->post_content );\n",{"type":41,"tag":204,"props":1350,"children":1352},{"class":206,"line":1351},108,[1353],{"type":41,"tag":204,"props":1354,"children":1355},{"emptyLinePlaceholder":301},[1356],{"type":47,"value":304},{"type":41,"tag":204,"props":1358,"children":1360},{"class":206,"line":1359},109,[1361],{"type":41,"tag":204,"props":1362,"children":1363},{},[1364],{"type":47,"value":1365},"        $issues = self::analyze( $content );\n",{"type":41,"tag":204,"props":1367,"children":1369},{"class":206,"line":1368},110,[1370],{"type":41,"tag":204,"props":1371,"children":1372},{"emptyLinePlaceholder":301},[1373],{"type":47,"value":304},{"type":41,"tag":204,"props":1375,"children":1377},{"class":206,"line":1376},111,[1378],{"type":41,"tag":204,"props":1379,"children":1380},{},[1381],{"type":47,"value":1382},"        $score = empty( $issues ) ? 100 : max( 0, 100 - ( count( $issues ) * 10 ) );\n",{"type":41,"tag":204,"props":1384,"children":1386},{"class":206,"line":1385},112,[1387],{"type":41,"tag":204,"props":1388,"children":1389},{"emptyLinePlaceholder":301},[1390],{"type":47,"value":304},{"type":41,"tag":204,"props":1392,"children":1394},{"class":206,"line":1393},113,[1395],{"type":41,"tag":204,"props":1396,"children":1397},{},[1398],{"type":47,"value":975},{"type":41,"tag":204,"props":1400,"children":1402},{"class":206,"line":1401},114,[1403],{"type":41,"tag":204,"props":1404,"children":1405},{},[1406],{"type":47,"value":1407},"            'score'   => $score,\n",{"type":41,"tag":204,"props":1409,"children":1411},{"class":206,"line":1410},115,[1412],{"type":41,"tag":204,"props":1413,"children":1414},{},[1415],{"type":47,"value":1416},"            'summary' => empty( $issues )\n",{"type":41,"tag":204,"props":1418,"children":1420},{"class":206,"line":1419},116,[1421],{"type":41,"tag":204,"props":1422,"children":1423},{},[1424],{"type":47,"value":1425},"                ? 'All checks passed.'\n",{"type":41,"tag":204,"props":1427,"children":1429},{"class":206,"line":1428},117,[1430],{"type":41,"tag":204,"props":1431,"children":1432},{},[1433],{"type":47,"value":1434},"                : sprintf( 'Found %d issues.', count( $issues ) ),\n",{"type":41,"tag":204,"props":1436,"children":1438},{"class":206,"line":1437},118,[1439],{"type":41,"tag":204,"props":1440,"children":1441},{},[1442],{"type":47,"value":1443},"            'issues'  => $issues,\n",{"type":41,"tag":204,"props":1445,"children":1447},{"class":206,"line":1446},119,[1448],{"type":41,"tag":204,"props":1449,"children":1450},{},[1451],{"type":47,"value":906},{"type":41,"tag":204,"props":1453,"children":1455},{"class":206,"line":1454},120,[1456],{"type":41,"tag":204,"props":1457,"children":1458},{},[1459],{"type":47,"value":915},{"type":41,"tag":204,"props":1461,"children":1463},{"class":206,"line":1462},121,[1464],{"type":41,"tag":204,"props":1465,"children":1466},{"emptyLinePlaceholder":301},[1467],{"type":47,"value":304},{"type":41,"tag":204,"props":1469,"children":1471},{"class":206,"line":1470},122,[1472],{"type":41,"tag":204,"props":1473,"children":1474},{},[1475],{"type":47,"value":1145},{"type":41,"tag":204,"props":1477,"children":1479},{"class":206,"line":1478},123,[1480],{"type":41,"tag":204,"props":1481,"children":1482},{},[1483],{"type":47,"value":1484},"     * Analyze content and return issues.\n",{"type":41,"tag":204,"props":1486,"children":1488},{"class":206,"line":1487},124,[1489],{"type":41,"tag":204,"props":1490,"children":1491},{},[1492],{"type":47,"value":1163},{"type":41,"tag":204,"props":1494,"children":1496},{"class":206,"line":1495},125,[1497],{"type":41,"tag":204,"props":1498,"children":1499},{},[1500],{"type":47,"value":1501},"     * @param string $content Plain text content.\n",{"type":41,"tag":204,"props":1503,"children":1505},{"class":206,"line":1504},126,[1506],{"type":41,"tag":204,"props":1507,"children":1508},{},[1509],{"type":47,"value":1510},"     * @return array Array of issue arrays with 'rule', 'message', 'severity'.\n",{"type":41,"tag":204,"props":1512,"children":1514},{"class":206,"line":1513},127,[1515],{"type":41,"tag":204,"props":1516,"children":1517},{},[1518],{"type":47,"value":1190},{"type":41,"tag":204,"props":1520,"children":1522},{"class":206,"line":1521},128,[1523],{"type":41,"tag":204,"props":1524,"children":1525},{},[1526],{"type":47,"value":1527},"    private static function analyze( string $content ): array {\n",{"type":41,"tag":204,"props":1529,"children":1531},{"class":206,"line":1530},129,[1532],{"type":41,"tag":204,"props":1533,"children":1534},{},[1535],{"type":47,"value":1536},"        $issues = array();\n",{"type":41,"tag":204,"props":1538,"children":1540},{"class":206,"line":1539},130,[1541],{"type":41,"tag":204,"props":1542,"children":1543},{"emptyLinePlaceholder":301},[1544],{"type":47,"value":304},{"type":41,"tag":204,"props":1546,"children":1548},{"class":206,"line":1547},131,[1549],{"type":41,"tag":204,"props":1550,"children":1551},{},[1552],{"type":47,"value":1553},"        \u002F\u002F Replace with your actual checks. Example:\n",{"type":41,"tag":204,"props":1555,"children":1557},{"class":206,"line":1556},132,[1558],{"type":41,"tag":204,"props":1559,"children":1560},{},[1561],{"type":47,"value":1562},"        \u002F\u002F if ( str_word_count( $content ) \u003C 300 ) {\n",{"type":41,"tag":204,"props":1564,"children":1566},{"class":206,"line":1565},133,[1567],{"type":41,"tag":204,"props":1568,"children":1569},{},[1570],{"type":47,"value":1571},"        \u002F\u002F     $issues[] = array(\n",{"type":41,"tag":204,"props":1573,"children":1575},{"class":206,"line":1574},134,[1576],{"type":41,"tag":204,"props":1577,"children":1578},{},[1579],{"type":47,"value":1580},"        \u002F\u002F         'rule'     => 'minimum-length',\n",{"type":41,"tag":204,"props":1582,"children":1584},{"class":206,"line":1583},135,[1585],{"type":41,"tag":204,"props":1586,"children":1587},{},[1588],{"type":47,"value":1589},"        \u002F\u002F         'message'  => 'Content is below the minimum word count of 300.',\n",{"type":41,"tag":204,"props":1591,"children":1593},{"class":206,"line":1592},136,[1594],{"type":41,"tag":204,"props":1595,"children":1596},{},[1597],{"type":47,"value":1598},"        \u002F\u002F         'severity' => 'warning',\n",{"type":41,"tag":204,"props":1600,"children":1602},{"class":206,"line":1601},137,[1603],{"type":41,"tag":204,"props":1604,"children":1605},{},[1606],{"type":47,"value":1607},"        \u002F\u002F     );\n",{"type":41,"tag":204,"props":1609,"children":1611},{"class":206,"line":1610},138,[1612],{"type":41,"tag":204,"props":1613,"children":1614},{},[1615],{"type":47,"value":1616},"        \u002F\u002F }\n",{"type":41,"tag":204,"props":1618,"children":1620},{"class":206,"line":1619},139,[1621],{"type":41,"tag":204,"props":1622,"children":1623},{"emptyLinePlaceholder":301},[1624],{"type":47,"value":304},{"type":41,"tag":204,"props":1626,"children":1628},{"class":206,"line":1627},140,[1629],{"type":41,"tag":204,"props":1630,"children":1631},{},[1632],{"type":47,"value":1633},"        return $issues;\n",{"type":41,"tag":204,"props":1635,"children":1637},{"class":206,"line":1636},141,[1638],{"type":41,"tag":204,"props":1639,"children":1640},{},[1641],{"type":47,"value":915},{"type":41,"tag":204,"props":1643,"children":1645},{"class":206,"line":1644},142,[1646],{"type":41,"tag":204,"props":1647,"children":1648},{},[1649],{"type":47,"value":365},{"type":41,"tag":56,"props":1651,"children":1653},{"id":1652},"availability",[1654],{"type":47,"value":1655},"Availability",{"type":41,"tag":50,"props":1657,"children":1658},{},[1659,1661,1667,1669,1675],{"type":47,"value":1660},"A tool that needs configuration -- an API key, an external service, a plugin that may not be installed -- declares ",{"type":41,"tag":94,"props":1662,"children":1664},{"className":1663},[],[1665],{"type":47,"value":1666},"meta.availability_callback",{"type":47,"value":1668},". ",{"type":41,"tag":94,"props":1670,"children":1672},{"className":1671},[],[1673],{"type":47,"value":1674},"AbilityExecutor",{"type":47,"value":1676}," gates execution on it, and the Tools page shows the result.",{"type":41,"tag":50,"props":1678,"children":1679},{},[1680,1682,1688,1690,1696],{"type":47,"value":1681},"Write it against the structured shape from the start. Returning a bare ",{"type":41,"tag":94,"props":1683,"children":1685},{"className":1684},[],[1686],{"type":47,"value":1687},"false",{"type":47,"value":1689}," still works and is still silent, but it discards the reason: the surface can then only say that ",{"type":41,"tag":1691,"props":1692,"children":1693},"em",{},[1694],{"type":47,"value":1695},"something",{"type":47,"value":1697}," is unconfigured, naming nothing and linking nowhere.",{"type":41,"tag":151,"props":1699,"children":1701},{"className":196,"code":1700,"language":198,"meta":159,"style":159},"use VIPWorkflows\\Abilities\\Availability;\nuse VIPWorkflows\\Abilities\\RequirementFactory;\nuse VIPWorkflows\\Abilities\\RequirementGroup;\n\n\u002F**\n * Whether this tool's dependencies are met, and what is missing if not.\n *\n * @return bool|Availability True when configured, otherwise the unmet requirements.\n *\u002F\npublic static function check_availability(): bool|Availability {\n    $settings = \\VIPWorkflows\\Abilities\\AbilitySettings::get_instance();\n    $options  = $settings->get_options( 'workflow-tool-{name}\u002F{slug}' );\n\n    if ( ! empty( $options['api_key'] ) ) {\n        return true;\n    }\n\n    return Availability::unmet(\n        RequirementGroup::all(\n            RequirementFactory::in_card(\n                'settings:workflow-tool-{name}',\n                __( '{Display Name} has no API key. Add it in the tool settings below.', 'workflow-tool-{name}' ),\n                __( '{Display Name} is not connected. Ask an administrator to connect it.', 'workflow-tool-{name}' ),\n                __( 'Complete the API key field below.', 'workflow-tool-{name}' ),\n                array( __( '{Display Name}', 'workflow-tool-{name}' ) )\n            )\n        )\n    );\n}\n",[1702],{"type":41,"tag":94,"props":1703,"children":1704},{"__ignoreMap":159},[1705,1713,1721,1729,1736,1743,1751,1758,1766,1773,1781,1789,1797,1804,1812,1820,1827,1834,1842,1850,1858,1866,1874,1882,1890,1898,1905,1913,1921],{"type":41,"tag":204,"props":1706,"children":1707},{"class":206,"line":207},[1708],{"type":41,"tag":204,"props":1709,"children":1710},{},[1711],{"type":47,"value":1712},"use VIPWorkflows\\Abilities\\Availability;\n",{"type":41,"tag":204,"props":1714,"children":1715},{"class":206,"line":216},[1716],{"type":41,"tag":204,"props":1717,"children":1718},{},[1719],{"type":47,"value":1720},"use VIPWorkflows\\Abilities\\RequirementFactory;\n",{"type":41,"tag":204,"props":1722,"children":1723},{"class":206,"line":225},[1724],{"type":41,"tag":204,"props":1725,"children":1726},{},[1727],{"type":47,"value":1728},"use VIPWorkflows\\Abilities\\RequirementGroup;\n",{"type":41,"tag":204,"props":1730,"children":1731},{"class":206,"line":234},[1732],{"type":41,"tag":204,"props":1733,"children":1734},{"emptyLinePlaceholder":301},[1735],{"type":47,"value":304},{"type":41,"tag":204,"props":1737,"children":1738},{"class":206,"line":243},[1739],{"type":41,"tag":204,"props":1740,"children":1741},{},[1742],{"type":47,"value":222},{"type":41,"tag":204,"props":1744,"children":1745},{"class":206,"line":252},[1746],{"type":41,"tag":204,"props":1747,"children":1748},{},[1749],{"type":47,"value":1750}," * Whether this tool's dependencies are met, and what is missing if not.\n",{"type":41,"tag":204,"props":1752,"children":1753},{"class":206,"line":261},[1754],{"type":41,"tag":204,"props":1755,"children":1756},{},[1757],{"type":47,"value":276},{"type":41,"tag":204,"props":1759,"children":1760},{"class":206,"line":270},[1761],{"type":41,"tag":204,"props":1762,"children":1763},{},[1764],{"type":47,"value":1765}," * @return bool|Availability True when configured, otherwise the unmet requirements.\n",{"type":41,"tag":204,"props":1767,"children":1768},{"class":206,"line":279},[1769],{"type":41,"tag":204,"props":1770,"children":1771},{},[1772],{"type":47,"value":294},{"type":41,"tag":204,"props":1774,"children":1775},{"class":206,"line":288},[1776],{"type":41,"tag":204,"props":1777,"children":1778},{},[1779],{"type":47,"value":1780},"public static function check_availability(): bool|Availability {\n",{"type":41,"tag":204,"props":1782,"children":1783},{"class":206,"line":297},[1784],{"type":41,"tag":204,"props":1785,"children":1786},{},[1787],{"type":47,"value":1788},"    $settings = \\VIPWorkflows\\Abilities\\AbilitySettings::get_instance();\n",{"type":41,"tag":204,"props":1790,"children":1791},{"class":206,"line":307},[1792],{"type":41,"tag":204,"props":1793,"children":1794},{},[1795],{"type":47,"value":1796},"    $options  = $settings->get_options( 'workflow-tool-{name}\u002F{slug}' );\n",{"type":41,"tag":204,"props":1798,"children":1799},{"class":206,"line":316},[1800],{"type":41,"tag":204,"props":1801,"children":1802},{"emptyLinePlaceholder":301},[1803],{"type":47,"value":304},{"type":41,"tag":204,"props":1805,"children":1806},{"class":206,"line":324},[1807],{"type":41,"tag":204,"props":1808,"children":1809},{},[1810],{"type":47,"value":1811},"    if ( ! empty( $options['api_key'] ) ) {\n",{"type":41,"tag":204,"props":1813,"children":1814},{"class":206,"line":333},[1815],{"type":41,"tag":204,"props":1816,"children":1817},{},[1818],{"type":47,"value":1819},"        return true;\n",{"type":41,"tag":204,"props":1821,"children":1822},{"class":206,"line":341},[1823],{"type":41,"tag":204,"props":1824,"children":1825},{},[1826],{"type":47,"value":915},{"type":41,"tag":204,"props":1828,"children":1829},{"class":206,"line":350},[1830],{"type":41,"tag":204,"props":1831,"children":1832},{"emptyLinePlaceholder":301},[1833],{"type":47,"value":304},{"type":41,"tag":204,"props":1835,"children":1836},{"class":206,"line":359},[1837],{"type":41,"tag":204,"props":1838,"children":1839},{},[1840],{"type":47,"value":1841},"    return Availability::unmet(\n",{"type":41,"tag":204,"props":1843,"children":1844},{"class":206,"line":368},[1845],{"type":41,"tag":204,"props":1846,"children":1847},{},[1848],{"type":47,"value":1849},"        RequirementGroup::all(\n",{"type":41,"tag":204,"props":1851,"children":1852},{"class":206,"line":376},[1853],{"type":41,"tag":204,"props":1854,"children":1855},{},[1856],{"type":47,"value":1857},"            RequirementFactory::in_card(\n",{"type":41,"tag":204,"props":1859,"children":1860},{"class":206,"line":385},[1861],{"type":41,"tag":204,"props":1862,"children":1863},{},[1864],{"type":47,"value":1865},"                'settings:workflow-tool-{name}',\n",{"type":41,"tag":204,"props":1867,"children":1868},{"class":206,"line":393},[1869],{"type":41,"tag":204,"props":1870,"children":1871},{},[1872],{"type":47,"value":1873},"                __( '{Display Name} has no API key. Add it in the tool settings below.', 'workflow-tool-{name}' ),\n",{"type":41,"tag":204,"props":1875,"children":1876},{"class":206,"line":590},[1877],{"type":41,"tag":204,"props":1878,"children":1879},{},[1880],{"type":47,"value":1881},"                __( '{Display Name} is not connected. Ask an administrator to connect it.', 'workflow-tool-{name}' ),\n",{"type":41,"tag":204,"props":1883,"children":1884},{"class":206,"line":599},[1885],{"type":41,"tag":204,"props":1886,"children":1887},{},[1888],{"type":47,"value":1889},"                __( 'Complete the API key field below.', 'workflow-tool-{name}' ),\n",{"type":41,"tag":204,"props":1891,"children":1892},{"class":206,"line":608},[1893],{"type":41,"tag":204,"props":1894,"children":1895},{},[1896],{"type":47,"value":1897},"                array( __( '{Display Name}', 'workflow-tool-{name}' ) )\n",{"type":41,"tag":204,"props":1899,"children":1900},{"class":206,"line":617},[1901],{"type":41,"tag":204,"props":1902,"children":1903},{},[1904],{"type":47,"value":897},{"type":41,"tag":204,"props":1906,"children":1907},{"class":206,"line":626},[1908],{"type":41,"tag":204,"props":1909,"children":1910},{},[1911],{"type":47,"value":1912},"        )\n",{"type":41,"tag":204,"props":1914,"children":1915},{"class":206,"line":635},[1916],{"type":41,"tag":204,"props":1917,"children":1918},{},[1919],{"type":47,"value":1920},"    );\n",{"type":41,"tag":204,"props":1922,"children":1923},{"class":206,"line":649},[1924],{"type":41,"tag":204,"props":1925,"children":1926},{},[1927],{"type":47,"value":365},{"type":41,"tag":50,"props":1929,"children":1930},{},[1931],{"type":47,"value":1932},"Rules:",{"type":41,"tag":1934,"props":1935,"children":1936},"ul",{},[1937,1970,2012,2044,2110,2136,2165],{"type":41,"tag":72,"props":1938,"children":1939},{},[1940,1945,1947,1953,1955,1961,1963,1968],{"type":41,"tag":76,"props":1941,"children":1942},{},[1943],{"type":47,"value":1944},"The callback owns satisfaction.",{"type":47,"value":1946}," Return ",{"type":41,"tag":94,"props":1948,"children":1950},{"className":1949},[],[1951],{"type":47,"value":1952},"true",{"type":47,"value":1954}," as soon as the dependencies are met; an ",{"type":41,"tag":94,"props":1956,"children":1958},{"className":1957},[],[1959],{"type":47,"value":1960},"Availability::unmet()",{"type":47,"value":1962}," carries ",{"type":41,"tag":1691,"props":1964,"children":1965},{},[1966],{"type":47,"value":1967},"only",{"type":47,"value":1969}," unmet requirements, and nothing downstream re-evaluates them.",{"type":41,"tag":72,"props":1971,"children":1972},{},[1973,1978,1980,1986,1988,1994,1996,2002,2004,2010],{"type":41,"tag":76,"props":1974,"children":1975},{},[1976],{"type":47,"value":1977},"A tool that generates text with AI does not write its own check.",{"type":47,"value":1979}," Generate through ",{"type":41,"tag":94,"props":1981,"children":1983},{"className":1982},[],[1984],{"type":47,"value":1985},"VIPWorkflows\\AI\\AiInference::get_instance()->model()",{"type":47,"value":1987},", never by naming a provider class, and gate with ",{"type":41,"tag":94,"props":1989,"children":1991},{"className":1990},[],[1992],{"type":47,"value":1993},"VIPWorkflows\\Abilities\\AiAvailability::for_selected_provider( $sources )",{"type":47,"value":1995},". That pair is the whole contract: the check resolves exactly the three conditions the resolver needs — the selected provider registered with the WordPress AI Client, its credential, and a chosen model — so the gate and the generation call cannot disagree. Naming a provider yourself is how a Claude-configured site ends up being told to go get an OpenAI key. ",{"type":41,"tag":94,"props":1997,"children":1999},{"className":1998},[],[2000],{"type":47,"value":2001},"for_provider( $provider, $sources )",{"type":47,"value":2003}," exists for the rare tool that genuinely requires one specific vendor. Do not call ",{"type":41,"tag":94,"props":2005,"children":2007},{"className":2006},[],[2008],{"type":47,"value":2009},"AiClient::isConfigured()",{"type":47,"value":2011}," in an availability callback — it makes a live request, and availability is read on every Tools-page load.",{"type":41,"tag":72,"props":2013,"children":2014},{},[2015,2026,2028,2034,2036,2042],{"type":41,"tag":76,"props":2016,"children":2017},{},[2018,2024],{"type":41,"tag":94,"props":2019,"children":2021},{"className":2020},[],[2022],{"type":47,"value":2023},"AiInference::model()",{"type":47,"value":2025}," returns null when the selection is unresolvable.",{"type":47,"value":2027}," There is no fallback to another vendor. Bail with a ",{"type":41,"tag":94,"props":2029,"children":2031},{"className":2030},[],[2032],{"type":47,"value":2033},"WP_Error",{"type":47,"value":2035}," rather than passing null to ",{"type":41,"tag":94,"props":2037,"children":2039},{"className":2038},[],[2040],{"type":47,"value":2041},"usingModel()",{"type":47,"value":2043},".",{"type":41,"tag":72,"props":2045,"children":2046},{},[2047,2060,2062,2068,2070,2076,2078,2084,2086,2092,2094,2100,2102,2108],{"type":41,"tag":76,"props":2048,"children":2049},{},[2050,2052,2058],{"type":47,"value":2051},"Build requirements with ",{"type":41,"tag":94,"props":2053,"children":2055},{"className":2054},[],[2056],{"type":47,"value":2057},"RequirementFactory",{"type":47,"value":2059},",",{"type":47,"value":2061}," not by hand. Use ",{"type":41,"tag":94,"props":2063,"children":2065},{"className":2064},[],[2066],{"type":47,"value":2067},"in_card()",{"type":47,"value":2069}," when the value is entered in the tool's own ",{"type":41,"tag":94,"props":2071,"children":2073},{"className":2072},[],[2074],{"type":47,"value":2075},"settings_schema",{"type":47,"value":2077}," fields; ",{"type":41,"tag":94,"props":2079,"children":2081},{"className":2080},[],[2082],{"type":47,"value":2083},"missing_credential( $service, $service_label, $sources )",{"type":47,"value":2085}," when the key is one the plugin reads through ",{"type":41,"tag":94,"props":2087,"children":2089},{"className":2088},[],[2090],{"type":47,"value":2091},"VIPWorkflows\\AI\\Credentials",{"type":47,"value":2093},", which resolves the destination against the install instead of hardcoding a screen; ",{"type":41,"tag":94,"props":2095,"children":2097},{"className":2096},[],[2098],{"type":47,"value":2099},"dependency()",{"type":47,"value":2101}," when a prerequisite other than a credential is missing (e.g. a required plugin is not installed); ",{"type":41,"tag":94,"props":2103,"children":2105},{"className":2104},[],[2106],{"type":47,"value":2107},"unsupported_environment()",{"type":47,"value":2109}," when nothing can be configured to fix it.",{"type":41,"tag":72,"props":2111,"children":2112},{},[2113,2118,2120,2126,2128,2134],{"type":41,"tag":76,"props":2114,"children":2115},{},[2116],{"type":47,"value":2117},"Supply both message registers.",{"type":47,"value":2119}," The admin reason may name a screen; the user message must not, because tools execute under ",{"type":41,"tag":94,"props":2121,"children":2123},{"className":2122},[],[2124],{"type":47,"value":2125},"edit_posts",{"type":47,"value":2127}," while admin settings require ",{"type":41,"tag":94,"props":2129,"children":2131},{"className":2130},[],[2132],{"type":47,"value":2133},"manage_options",{"type":47,"value":2135},". The register is chosen where the requirement is read, not where it is authored.",{"type":41,"tag":72,"props":2137,"children":2138},{},[2139,2141,2147,2149,2155,2157,2163],{"type":47,"value":2140},"Group with ",{"type":41,"tag":94,"props":2142,"children":2144},{"className":2143},[],[2145],{"type":47,"value":2146},"RequirementGroup::all()",{"type":47,"value":2148},", or ",{"type":41,"tag":94,"props":2150,"children":2152},{"className":2151},[],[2153],{"type":47,"value":2154},"RequirementGroup::any()",{"type":47,"value":2156}," when satisfying one member is enough -- an ",{"type":41,"tag":94,"props":2158,"children":2160},{"className":2159},[],[2161],{"type":47,"value":2162},"any",{"type":47,"value":2164}," group renders as one \"configure at least one of\" block.",{"type":41,"tag":72,"props":2166,"children":2167},{},[2168,2170,2175],{"type":47,"value":2169},"Returning ",{"type":41,"tag":94,"props":2171,"children":2173},{"className":2172},[],[2174],{"type":47,"value":1687},{"type":47,"value":2176}," remains valid for a tool with nothing useful to say. It produces the generic line, with no diagnostic.",{"type":41,"tag":56,"props":2178,"children":2180},{"id":2179},"registration-rules",[2181],{"type":47,"value":2182},"Registration Rules",{"type":41,"tag":1934,"props":2184,"children":2185},{},[2186,2214,2231,2279,2290,2308,2319,2330],{"type":41,"tag":72,"props":2187,"children":2188},{},[2189,2191,2196,2198,2204,2206,2212],{"type":47,"value":2190},"The ability name ",{"type":41,"tag":76,"props":2192,"children":2193},{},[2194],{"type":47,"value":2195},"must",{"type":47,"value":2197}," be namespaced with a slash: ",{"type":41,"tag":94,"props":2199,"children":2201},{"className":2200},[],[2202],{"type":47,"value":2203},"plugin-slug\u002Fability-slug",{"type":47,"value":2205},". Never use ",{"type":41,"tag":94,"props":2207,"children":2209},{"className":2208},[],[2210],{"type":47,"value":2211},"sanitize_key()",{"type":47,"value":2213}," on ability IDs (it strips slashes).",{"type":41,"tag":72,"props":2215,"children":2216},{},[2217,2223,2225],{"type":41,"tag":94,"props":2218,"children":2220},{"className":2219},[],[2221],{"type":47,"value":2222},"category",{"type":47,"value":2224}," must be ",{"type":41,"tag":94,"props":2226,"children":2228},{"className":2227},[],[2229],{"type":47,"value":2230},"'vip-workflows'",{"type":41,"tag":72,"props":2232,"children":2233},{},[2234,2245,2247,2253,2255,2261,2263,2269,2271,2277],{"type":41,"tag":76,"props":2235,"children":2236},{},[2237,2243],{"type":41,"tag":94,"props":2238,"children":2240},{"className":2239},[],[2241],{"type":47,"value":2242},"meta.type",{"type":47,"value":2244}," is required",{"type":47,"value":2246}," for the tool to appear in Integrations > Tools. Use ",{"type":41,"tag":94,"props":2248,"children":2250},{"className":2249},[],[2251],{"type":47,"value":2252},"'check'",{"type":47,"value":2254}," for validation tools, ",{"type":41,"tag":94,"props":2256,"children":2258},{"className":2257},[],[2259],{"type":47,"value":2260},"'helper'",{"type":47,"value":2262}," for content generators, ",{"type":41,"tag":94,"props":2264,"children":2266},{"className":2265},[],[2267],{"type":47,"value":2268},"'validator'",{"type":47,"value":2270}," for analysis tools, ",{"type":41,"tag":94,"props":2272,"children":2274},{"className":2273},[],[2275],{"type":47,"value":2276},"'agent'",{"type":47,"value":2278}," for AI Agent.",{"type":41,"tag":72,"props":2280,"children":2281},{},[2282,2288],{"type":41,"tag":94,"props":2283,"children":2285},{"className":2284},[],[2286],{"type":47,"value":2287},"meta.transition_eligible = true",{"type":47,"value":2289}," if the tool should run during workflow or phase transitions",{"type":41,"tag":72,"props":2291,"children":2292},{},[2293,2299,2301,2306],{"type":41,"tag":94,"props":2294,"children":2296},{"className":2295},[],[2297],{"type":47,"value":2298},"meta.show_in_commands = true",{"type":47,"value":2300}," to expose the \"Show in Command Palette (⌘K)\" toggle in Integrations > Tools; admins control the actual value per-site. Omit or set ",{"type":41,"tag":94,"props":2302,"children":2304},{"className":2303},[],[2305],{"type":47,"value":1687},{"type":47,"value":2307}," for tools that should never appear in the palette.",{"type":41,"tag":72,"props":2309,"children":2310},{},[2311,2313],{"type":47,"value":2312},"Hook into ",{"type":41,"tag":94,"props":2314,"children":2316},{"className":2315},[],[2317],{"type":47,"value":2318},"wp_abilities_api_init",{"type":41,"tag":72,"props":2320,"children":2321},{},[2322,2324],{"type":47,"value":2323},"Guard with ",{"type":41,"tag":94,"props":2325,"children":2327},{"className":2326},[],[2328],{"type":47,"value":2329},"function_exists( 'vip_workflows_register_ability' )",{"type":41,"tag":72,"props":2331,"children":2332},{},[2333,2335,2340,2342,2348,2350,2356,2358,2364,2366,2372,2374,2379],{"type":47,"value":2334},"For ",{"type":41,"tag":76,"props":2336,"children":2337},{},[2338],{"type":47,"value":2339},"phase transition tools",{"type":47,"value":2341}," (ideation to pitch\u002Feditorial): the input receives ",{"type":41,"tag":94,"props":2343,"children":2345},{"className":2344},[],[2346],{"type":47,"value":2347},"project_id",{"type":47,"value":2349}," (not ",{"type":41,"tag":94,"props":2351,"children":2353},{"className":2352},[],[2354],{"type":47,"value":2355},"post_id",{"type":47,"value":2357},"). Do not use ",{"type":41,"tag":94,"props":2359,"children":2361},{"className":2360},[],[2362],{"type":47,"value":2363},"current_user_can( 'edit_post', ... )",{"type":47,"value":2365}," in ",{"type":41,"tag":94,"props":2367,"children":2369},{"className":2368},[],[2370],{"type":47,"value":2371},"permission_callback",{"type":47,"value":2373}," because ideation CPTs use custom capabilities. Validate input and return ",{"type":41,"tag":94,"props":2375,"children":2377},{"className":2376},[],[2378],{"type":47,"value":1952},{"type":47,"value":2043},{"type":41,"tag":56,"props":2381,"children":2383},{"id":2382},"output-contract",[2384],{"type":47,"value":2385},"Output Contract",{"type":41,"tag":50,"props":2387,"children":2388},{},[2389,2394,2396,2402],{"type":41,"tag":76,"props":2390,"children":2391},{},[2392],{"type":47,"value":2393},"Declare what your tool returns.",{"type":47,"value":2395}," Set ",{"type":41,"tag":94,"props":2397,"children":2399},{"className":2398},[],[2400],{"type":47,"value":2401},"meta.result_type",{"type":47,"value":2403}," to one of three values.\nThe result modal switches on that declaration rather than inspecting your output\nkeys, so a shape it has never seen still renders correctly.",{"type":41,"tag":50,"props":2405,"children":2406},{},[2407,2409,2415],{"type":47,"value":2408},"Do not skip this. Before ",{"type":41,"tag":94,"props":2410,"children":2412},{"className":2411},[],[2413],{"type":47,"value":2414},"result_type",{"type":47,"value":2416}," existed the modal guessed by probing keys\nin priority order, and every new shape either matched no key and rendered an empty\nmodal or matched the wrong key and applied the wrong value to a field. A tool that\ndeclares nothing still falls back to that guessing.",{"type":41,"tag":182,"props":2418,"children":2420},{"id":2419},"result_type-report-a-verdict-with-findings",[2421,2427],{"type":41,"tag":94,"props":2422,"children":2424},{"className":2423},[],[2425],{"type":47,"value":2426},"result_type => 'report'",{"type":47,"value":2428}," — a verdict with findings",{"type":41,"tag":50,"props":2430,"children":2431},{},[2432],{"type":47,"value":2433},"For checks. Also the shape a transition gate reads.",{"type":41,"tag":1934,"props":2435,"children":2436},{},[2437,2478,2489,2500],{"type":41,"tag":72,"props":2438,"children":2439},{},[2440,2446,2448,2454,2456,2462,2464,2470,2471,2476],{"type":41,"tag":94,"props":2441,"children":2443},{"className":2442},[],[2444],{"type":47,"value":2445},"status",{"type":47,"value":2447}," (string) -- ",{"type":41,"tag":94,"props":2449,"children":2451},{"className":2450},[],[2452],{"type":47,"value":2453},"'pass'",{"type":47,"value":2455},", ",{"type":41,"tag":94,"props":2457,"children":2459},{"className":2458},[],[2460],{"type":47,"value":2461},"'warning'",{"type":47,"value":2463}," or ",{"type":41,"tag":94,"props":2465,"children":2467},{"className":2466},[],[2468],{"type":47,"value":2469},"'fail'",{"type":47,"value":1668},{"type":41,"tag":76,"props":2472,"children":2473},{},[2474],{"type":47,"value":2475},"Always set it.",{"type":47,"value":2477}," Omitting\nit means \"no verdict\", which is not the same as failing.",{"type":41,"tag":72,"props":2479,"children":2480},{},[2481,2487],{"type":41,"tag":94,"props":2482,"children":2484},{"className":2483},[],[2485],{"type":47,"value":2486},"score",{"type":47,"value":2488}," (number, 0-100) -- optional",{"type":41,"tag":72,"props":2490,"children":2491},{},[2492,2498],{"type":41,"tag":94,"props":2493,"children":2495},{"className":2494},[],[2496],{"type":47,"value":2497},"summary",{"type":47,"value":2499}," (string) -- one line about the result",{"type":41,"tag":72,"props":2501,"children":2502},{},[2503,2509,2511,2517,2518,2524,2525,2531,2533,2539,2540,2545,2546,2552],{"type":41,"tag":94,"props":2504,"children":2506},{"className":2505},[],[2507],{"type":47,"value":2508},"issues",{"type":47,"value":2510}," (array) -- each issue has ",{"type":41,"tag":94,"props":2512,"children":2514},{"className":2513},[],[2515],{"type":47,"value":2516},"rule",{"type":47,"value":2455},{"type":41,"tag":94,"props":2519,"children":2521},{"className":2520},[],[2522],{"type":47,"value":2523},"message",{"type":47,"value":2455},{"type":41,"tag":94,"props":2526,"children":2528},{"className":2527},[],[2529],{"type":47,"value":2530},"severity",{"type":47,"value":2532}," (",{"type":41,"tag":94,"props":2534,"children":2536},{"className":2535},[],[2537],{"type":47,"value":2538},"'error'",{"type":47,"value":2455},{"type":41,"tag":94,"props":2541,"children":2543},{"className":2542},[],[2544],{"type":47,"value":2461},{"type":47,"value":2455},{"type":41,"tag":94,"props":2547,"children":2549},{"className":2548},[],[2550],{"type":47,"value":2551},"'info'",{"type":47,"value":2553},")",{"type":41,"tag":182,"props":2555,"children":2557},{"id":2556},"result_type-value-one-value-that-replaces-a-field",[2558,2564],{"type":41,"tag":94,"props":2559,"children":2561},{"className":2560},[],[2562],{"type":47,"value":2563},"result_type => 'value'",{"type":47,"value":2565}," — one value that replaces a field",{"type":41,"tag":50,"props":2567,"children":2568},{},[2569],{"type":47,"value":2570},"For generators: an excerpt, a rewritten paragraph.",{"type":41,"tag":1934,"props":2572,"children":2573},{},[2574,2592],{"type":41,"tag":72,"props":2575,"children":2576},{},[2577,2583,2584,2590],{"type":41,"tag":94,"props":2578,"children":2580},{"className":2579},[],[2581],{"type":47,"value":2582},"excerpt",{"type":47,"value":2463},{"type":41,"tag":94,"props":2585,"children":2587},{"className":2586},[],[2588],{"type":47,"value":2589},"content",{"type":47,"value":2591}," (string) -- the value itself",{"type":41,"tag":72,"props":2593,"children":2594},{},[2595,2600],{"type":41,"tag":94,"props":2596,"children":2598},{"className":2597},[],[2599],{"type":47,"value":2497},{"type":47,"value":2601}," (string) -- optional",{"type":41,"tag":50,"props":2603,"children":2604},{},[2605,2607,2613],{"type":47,"value":2606},"Pair it with ",{"type":41,"tag":94,"props":2608,"children":2610},{"className":2609},[],[2611],{"type":47,"value":2612},"meta.apply_field",{"type":47,"value":2614}," naming the field the value belongs in, or the\nwriter gets no way to use it.",{"type":41,"tag":182,"props":2616,"children":2618},{"id":2617},"result_type-list-several-options-to-choose-from",[2619,2625],{"type":41,"tag":94,"props":2620,"children":2622},{"className":2621},[],[2623],{"type":47,"value":2624},"result_type => 'list'",{"type":47,"value":2626}," — several options to choose from",{"type":41,"tag":50,"props":2628,"children":2629},{},[2630],{"type":47,"value":2631},"For suggestions: alternative headlines, related links.",{"type":41,"tag":1934,"props":2633,"children":2634},{},[2635,2679],{"type":41,"tag":72,"props":2636,"children":2637},{},[2638,2644,2646],{"type":41,"tag":94,"props":2639,"children":2641},{"className":2640},[],[2642],{"type":47,"value":2643},"suggestions",{"type":47,"value":2645}," (array) -- one of two row shapes:\n",{"type":41,"tag":1934,"props":2647,"children":2648},{},[2649,2668],{"type":41,"tag":72,"props":2650,"children":2651},{},[2652,2654,2659,2661,2666],{"type":47,"value":2653},"a ",{"type":41,"tag":76,"props":2655,"children":2656},{},[2657],{"type":47,"value":2658},"plain string",{"type":47,"value":2660},", when the row ",{"type":41,"tag":1691,"props":2662,"children":2663},{},[2664],{"type":47,"value":2665},"is",{"type":47,"value":2667}," a value a field can be set to (an\nalternative headline)",{"type":41,"tag":72,"props":2669,"children":2670},{},[2671,2677],{"type":41,"tag":94,"props":2672,"children":2674},{"className":2673},[],[2675],{"type":47,"value":2676},"array( 'label' => …, 'meta' => …, 'href' => … )",{"type":47,"value":2678},", when the row points\nsomewhere instead (a suggested link, whose label is anchor text)",{"type":41,"tag":72,"props":2680,"children":2681},{},[2682,2687],{"type":41,"tag":94,"props":2683,"children":2685},{"className":2684},[],[2686],{"type":47,"value":2497},{"type":47,"value":2688}," (string) -- one line above the list",{"type":41,"tag":50,"props":2690,"children":2691},{},[2692,2694,2700],{"type":47,"value":2693},"Only plain-string rows get an apply action, because only they are a value. Set\n",{"type":41,"tag":94,"props":2695,"children":2697},{"className":2696},[],[2698],{"type":47,"value":2699},"apply_field",{"type":47,"value":2701}," for those.",{"type":41,"tag":182,"props":2703,"children":2705},{"id":2704},"summary-is-never-a-value",[2706,2711],{"type":41,"tag":94,"props":2707,"children":2709},{"className":2708},[],[2710],{"type":47,"value":2497},{"type":47,"value":2712}," is never a value",{"type":41,"tag":50,"props":2714,"children":2715},{},[2716,2718,2723,2725,2731],{"type":47,"value":2717},"It is the line ",{"type":41,"tag":1691,"props":2719,"children":2720},{},[2721],{"type":47,"value":2722},"about",{"type":47,"value":2724}," a result. It is displayed, never applied. A tool that\nreturned ",{"type":41,"tag":94,"props":2726,"children":2728},{"className":2727},[],[2729],{"type":47,"value":2730},"'5 suggested headlines.'",{"type":47,"value":2732}," as its summary once had that written into a\npost title, because the modal treated the summary as content to apply.",{"type":41,"tag":56,"props":2734,"children":2736},{"id":2735},"testing",[2737],{"type":47,"value":2738},"Testing",{"type":41,"tag":68,"props":2740,"children":2741},{},[2742,2752,2757,2762],{"type":41,"tag":72,"props":2743,"children":2744},{},[2745,2747],{"type":47,"value":2746},"Place the plugin directory alongside ",{"type":41,"tag":94,"props":2748,"children":2750},{"className":2749},[],[2751],{"type":47,"value":172},{"type":41,"tag":72,"props":2753,"children":2754},{},[2755],{"type":47,"value":2756},"Activate it in WordPress admin",{"type":41,"tag":72,"props":2758,"children":2759},{},[2760],{"type":47,"value":2761},"Go to Integrations > Tools to verify it appears",{"type":41,"tag":72,"props":2763,"children":2764},{},[2765],{"type":47,"value":2766},"Open a post in the editor; the tool should appear in the sidebar",{"type":41,"tag":2768,"props":2769,"children":2770},"style",{},[2771],{"type":47,"value":2772},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":2774,"total":225},[2775,2787,2807],{"slug":2776,"name":2776,"fn":2777,"description":2778,"org":2779,"tags":2780,"stars":22,"repoUrl":23,"updatedAt":2786},"create-vip-workflows-agent","scaffold VIP Workflows agent plugins","Scaffold a VIP Workflows agent plugin. Use when the user wants to create a research agent, a story discovery source, an AI-stage agent, or a combined agent that provides multiple capabilities for VIP Workflows.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2781,2784,2785],{"name":2782,"slug":2783,"type":15},"Agents","agents",{"name":17,"slug":18,"type":15},{"name":13,"slug":14,"type":15},"2026-09-04T08:01:04.234021",{"slug":2788,"name":2788,"fn":2789,"description":2790,"org":2791,"tags":2792,"stars":22,"repoUrl":23,"updatedAt":2806},"create-vip-workflows-notification-channel","scaffold VIP Workflows notification plugins","Scaffold a VIP Workflows notification channel plugin. Use when the user wants to add a custom notification destination like Slack, Teams, Discord, SMS, or any webhook-based service to VIP Workflows.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2793,2796,2799,2800,2803],{"name":2794,"slug":2795,"type":15},"Automation","automation",{"name":2797,"slug":2798,"type":15},"Microsoft Teams","microsoft-teams",{"name":17,"slug":18,"type":15},{"name":2801,"slug":2802,"type":15},"Slack","slack",{"name":2804,"slug":2805,"type":15},"Webhooks","webhooks","2026-09-04T08:00:43.363392",{"slug":4,"name":4,"fn":5,"description":6,"org":2808,"tags":2809,"stars":22,"repoUrl":23,"updatedAt":24},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2810,2811,2812],{"name":20,"slug":21,"type":15},{"name":17,"slug":18,"type":15},{"name":13,"slug":14,"type":15},{"items":2814,"total":1193},[2815,2836,2853,2867,2880,2897,2912,2924,2939,2956,2967,2982],{"slug":2816,"name":2816,"fn":2817,"description":2818,"org":2819,"tags":2820,"stars":2833,"repoUrl":2834,"updatedAt":2835},"annotate","collect visual feedback with browser annotation tools","Open a browser with visual annotation tools. The user clicks elements on their site and leaves feedback — the agent reads annotations and makes changes. Use this when the user wants to point at specific elements to fix, tweak, or redesign.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2821,2824,2827,2830],{"name":2822,"slug":2823,"type":15},"Frontend","frontend",{"name":2825,"slug":2826,"type":15},"Productivity","productivity",{"name":2828,"slug":2829,"type":15},"UX Copy","ux-copy",{"name":2831,"slug":2832,"type":15},"UX Design","ux-design",484,"https:\u002F\u002Fgithub.com\u002FAutomattic\u002Fstudio","2026-05-06T05:40:01.516544",{"slug":2837,"name":2837,"fn":2838,"description":2839,"org":2840,"tags":2841,"stars":2833,"repoUrl":2834,"updatedAt":2852},"block-content","write editable WordPress block markup","Write editable WordPress block markup for local Studio sites, including core\u002Fhtml limits, block-theme layout rules, full-width sections, validation, and skeleton-first page\u002FCSS recipes.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2842,2845,2848,2851],{"name":2843,"slug":2844,"type":15},"Block Editor","block-editor",{"name":2846,"slug":2847,"type":15},"CSS","css",{"name":2849,"slug":2850,"type":15},"HTML","html",{"name":13,"slug":14,"type":15},"2026-08-29T09:23:44.042569",{"slug":2854,"name":2854,"fn":2855,"description":2856,"org":2857,"tags":2858,"stars":2833,"repoUrl":2834,"updatedAt":2866},"hosting-plans-helper","provide WordPress.com hosting plan information","Answer WordPress.com plan, pricing, upgrade, and feature-tier questions (plan names, what each tier unlocks — plugins, themes, custom code, SSH, hosting — and current prices) from authoritative live data. Load before answering ANY plan, pricing, or feature-gating question; never answer these from memory.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2859,2862,2865],{"name":2860,"slug":2861,"type":15},"Pricing","pricing",{"name":2863,"slug":2864,"type":15},"Reference","reference",{"name":13,"slug":14,"type":15},"2026-07-02T07:42:33.654791",{"slug":2868,"name":2868,"fn":2869,"description":2870,"org":2871,"tags":2872,"stars":2833,"repoUrl":2834,"updatedAt":2879},"imagery","generate AI images for websites","Generate AI images for a site with generate_images — how to write image specs, pick aspect ratios, place files (theme assets vs media library), and handle failures.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2873,2876],{"name":2874,"slug":2875,"type":15},"Creative","creative",{"name":2877,"slug":2878,"type":15},"Image Generation","image-generation","2026-09-01T08:30:34.994105",{"slug":2881,"name":2881,"fn":2882,"description":2883,"org":2884,"tags":2885,"stars":2833,"repoUrl":2834,"updatedAt":2896},"liberate","migrate websites to WordPress","Import and rebuild a website from a closed platform (Wix, Squarespace, Webflow, Shopify, GoDaddy, Hostinger, HubSpot, Weebly) into a Studio WordPress site. Extracts pages\u002Fposts\u002Fproducts + media, then reconstructs the design as editable blocks + WooCommerce OR as a high-fidelity replica theme. Invoke when the user wants to migrate, import, liberate, or rebuild a site from one of these platforms.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2886,2889,2892,2895],{"name":2887,"slug":2888,"type":15},"CMS","cms",{"name":2890,"slug":2891,"type":15},"Migration","migration",{"name":2893,"slug":2894,"type":15},"Web Development","web-development",{"name":13,"slug":14,"type":15},"2026-07-09T06:47:33.454311",{"slug":2898,"name":2898,"fn":2899,"description":2900,"org":2901,"tags":2902,"stars":2833,"repoUrl":2834,"updatedAt":2911},"need-for-speed","run frontend performance audits for WordPress sites","Run a frontend performance audit on a WordPress site and get actionable optimization recommendations.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2903,2906,2907,2910],{"name":2904,"slug":2905,"type":15},"Audit","audit",{"name":2822,"slug":2823,"type":15},{"name":2908,"slug":2909,"type":15},"Performance","performance",{"name":13,"slug":14,"type":15},"2026-05-06T05:40:06.433267",{"slug":2913,"name":2913,"fn":2914,"description":2915,"org":2916,"tags":2917,"stars":2833,"repoUrl":2834,"updatedAt":2923},"plugin-recommendations","recommend WordPress plugins for site features","Choose recommended plugins and plugin-provided blocks for features core WordPress blocks do not cover - ecommerce (WooCommerce), forms and newsletters (Jetpack), online courses and quizzes (Sensei LMS), polls, surveys and ratings (Crowdsignal), spam protection (Akismet) - while keeping generated content editable and avoiding raw HTML fallbacks. Any request to sell products or build a shop, store, or storefront requires WooCommerce with products.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2918,2921,2922],{"name":2919,"slug":2920,"type":15},"Content Creation","content-creation",{"name":17,"slug":18,"type":15},{"name":13,"slug":14,"type":15},"2026-08-22T03:27:47.937007",{"slug":2925,"name":2925,"fn":2926,"description":2927,"org":2928,"tags":2929,"stars":2833,"repoUrl":2834,"updatedAt":2938},"rank-me-up","run on-page SEO audits for WordPress sites","Run an on-page SEO audit on a WordPress site and get actionable recommendations to improve search visibility.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2930,2931,2934,2937],{"name":2904,"slug":2905,"type":15},{"name":2932,"slug":2933,"type":15},"Marketing","marketing",{"name":2935,"slug":2936,"type":15},"SEO","seo",{"name":13,"slug":14,"type":15},"2026-05-06T05:40:05.196367",{"slug":2940,"name":2940,"fn":2941,"description":2942,"org":2943,"tags":2944,"stars":2833,"repoUrl":2834,"updatedAt":2955},"site-spec","gather specifications for new WordPress sites","Gather the site name and layout preference before building a WordPress site. Run this before creating any new site.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2945,2948,2951,2954],{"name":2946,"slug":2947,"type":15},"Design","design",{"name":2949,"slug":2950,"type":15},"Product Management","product-management",{"name":2952,"slug":2953,"type":15},"Specs","specs",{"name":13,"slug":14,"type":15},"2026-05-06T05:40:02.739409",{"slug":2957,"name":2957,"fn":2958,"description":2959,"org":2960,"tags":2961,"stars":2833,"repoUrl":2834,"updatedAt":2966},"studio-cli","manage local WordPress sites with Studio CLI","Use the Studio CLI to manage local WordPress sites, authentication, and preview sites. Invoke this skill when you need to run Studio CLI commands, manage sites, or troubleshoot site issues.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2962,2965],{"name":2963,"slug":2964,"type":15},"CLI","cli",{"name":13,"slug":14,"type":15},"2026-09-04T07:24:24.148676",{"slug":2968,"name":2968,"fn":2969,"description":2970,"org":2971,"tags":2972,"stars":2833,"repoUrl":2834,"updatedAt":2981},"taxonomist","optimize WordPress category taxonomy","Analyze and optimize a WordPress site's category taxonomy. Exports all posts, uses AI to suggest an improved category structure — merging duplicates, retiring dead categories, creating missing ones, writing descriptions, and re-categorizing posts. Run this when the user wants to clean up or improve their categories.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2973,2976,2979,2980],{"name":2974,"slug":2975,"type":15},"Content Strategy","content-strategy",{"name":2977,"slug":2978,"type":15},"Data Cleaning","data-cleaning",{"name":2935,"slug":2936,"type":15},{"name":13,"slug":14,"type":15},"2026-05-06T05:40:03.966799",{"slug":2983,"name":2983,"fn":2984,"description":2985,"org":2986,"tags":2987,"stars":2833,"repoUrl":2834,"updatedAt":2997},"visual-design","plan and execute visual design direction","Plan and execute high-quality visual direction for site creation, redesign, layout, typography, color, motion, and visual polish.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2988,2991,2992,2995],{"name":2989,"slug":2990,"type":15},"Animation","animation",{"name":2946,"slug":2947,"type":15},{"name":2993,"slug":2994,"type":15},"Typography","typography",{"name":2996,"slug":2983,"type":15},"Visual Design","2026-07-24T05:40:57.887452"]