[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-automattic-create-vip-workflows-notification-channel":3,"mdc-1hzmbv-key":42,"related-org-automattic-create-vip-workflows-notification-channel":2055,"related-repo-automattic-create-vip-workflows-notification-channel":2241},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":28,"repoUrl":29,"updatedAt":30,"license":31,"forks":32,"topics":33,"repo":37,"sourceUrl":40,"mdContent":41},"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},"automattic","Automattic","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fautomattic.png",[12,16,19,22,25],{"name":13,"slug":14,"type":15},"Automation","automation","tag",{"name":17,"slug":18,"type":15},"Plugin Development","plugin-development",{"name":20,"slug":21,"type":15},"Microsoft Teams","microsoft-teams",{"name":23,"slug":24,"type":15},"Slack","slack",{"name":26,"slug":27,"type":15},"Webhooks","webhooks",150,"https:\u002F\u002Fgithub.com\u002FAutomattic\u002Fvip-go-mu-plugins-built","2026-09-04T08:00:43.363392",null,38,[34,35,36],"vip","vip-go","wordpress",{"repoUrl":29,"stars":28,"forks":32,"topics":38,"description":39},[34,35,36],"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-notification-channel","---\nname: create-vip-workflows-notification-channel\ndescription: >-\n  Scaffold a VIP Workflows notification channel plugin. Use when the user wants\n  to add a custom notification destination like Slack, Teams, Discord, SMS,\n  or any webhook-based service to VIP Workflows.\n---\n# Create a VIP Workflows Notification Channel\n\nNotification channels deliver workflow event notifications (status changes, SLA breaches, publishing alerts) to external services. Each channel is a standalone WordPress plugin that extends the `NotificationChannel` base class.\n\n## Requirements\n\nBefore starting, gather from the user:\n1. **Destination service** -- e.g., Slack, Discord, Teams, Twilio SMS, PagerDuty\n2. **Plugin slug** -- e.g., `workflow-channel-slack`\n3. **What credentials are needed?** -- webhook URL, API token, phone number, etc.\n4. **Does it support a test\u002Fping?** -- most webhook services do\n\n## Plugin Structure\n\n```\nworkflow-channel-{name}\u002F\n  workflow-channel-{name}.php       # Main plugin file (hooks + asset loading)\n  includes\u002F\n    class-{name}-channel.php        # Channel class extending NotificationChannel\n```\n\nThe plugin directory lives alongside `vip-workflows\u002F` in the same parent directory.\n\n## Boilerplate\n\n### Main plugin file: `workflow-channel-{name}\u002Fworkflow-channel-{name}.php`\n\n```php\n\u003C?php\n\u002F**\n * Plugin Name: Workflow {Display Name} Channel\n * Description: Sends VIP Workflows notifications to {service}.\n * Version: 1.0.0\n * Requires Plugins: vip-workflows\n * Text Domain: workflow-channel-{name}\n *\n * @package WorkflowChannel{PascalName}\n *\u002F\n\ndeclare( strict_types=1 );\n\nnamespace WorkflowChannel{PascalName};\n\nif ( ! defined( 'ABSPATH' ) ) {\n    exit;\n}\n\ndefine( 'WORKFLOW_CHANNEL_{UPPER_NAME}_DIR', plugin_dir_path( __FILE__ ) );\n\nadd_action( 'vip_workflows_register_notification_channels', function( $dispatcher ) {\n    require_once WORKFLOW_CHANNEL_{UPPER_NAME}_DIR . 'includes\u002Fclass-{name}-channel.php';\n    $dispatcher->register_channel( new {PascalName}Channel() );\n} );\n```\n\n### Channel class: `workflow-channel-{name}\u002Fincludes\u002Fclass-{name}-channel.php`\n\n```php\n\u003C?php\ndeclare( strict_types=1 );\n\nnamespace WorkflowChannel{PascalName};\n\nuse VIPWorkflows\\Notifications\\NotificationChannel;\nuse VIPWorkflows\\Notifications\\Notification;\nuse WP_Error;\n\nclass {PascalName}Channel extends NotificationChannel {\n\n    public function get_id(): string {\n        return '{name}';\n    }\n\n    public function get_name(): string {\n        return __( '{Display Name}', 'workflow-channel-{name}' );\n    }\n\n    public function get_description(): string {\n        return __( 'Send notifications to {service}.', 'workflow-channel-{name}' );\n    }\n\n    public function get_icon(): string {\n        return 'search';\n    }\n\n    \u002F**\n     * Check if the channel has the required configuration to send.\n     *\u002F\n    public function is_configured(): bool {\n        $settings = $this->get_settings();\n        return ! empty( $settings['webhook_url'] );\n    }\n\n    \u002F**\n     * Define settings fields. Auto-rendered in the admin UI.\n     *\u002F\n    public function get_settings_schema(): array {\n        return array(\n            'webhook_url' => array(\n                'type'        => 'string',\n                'label'       => __( 'Webhook URL', 'workflow-channel-{name}' ),\n                'description' => __( 'The incoming webhook URL from {service}.', 'workflow-channel-{name}' ),\n                'required'    => true,\n            ),\n            \u002F\u002F Add more fields as needed:\n            \u002F\u002F 'channel' => array(\n            \u002F\u002F     'type'    => 'string',\n            \u002F\u002F     'label'   => __( 'Channel', 'workflow-channel-{name}' ),\n            \u002F\u002F     'default' => '#general',\n            \u002F\u002F ),\n        );\n    }\n\n    \u002F**\n     * Send a notification to the service.\n     *\n     * @param Notification $notification Contains ->get_subject(), ->get_body(),\n     *                                   ->get_post_id(), ->get_event_type(), etc.\n     * @return bool True on success.\n     *\u002F\n    public function send( Notification $notification ): bool {\n        $settings    = $this->get_settings();\n        $webhook_url = $settings['webhook_url'] ?? '';\n\n        if ( empty( $webhook_url ) ) {\n            return false;\n        }\n\n        \u002F\u002F Build the payload for your service.\n        \u002F\u002F Adapt this to match the service's expected format.\n        $payload = array(\n            'text' => sprintf(\n                \"**%s**\\n%s\",\n                $notification->get_subject(),\n                $notification->get_body()\n            ),\n        );\n\n        $response = wp_remote_post( $webhook_url, array(\n            'headers' => array( 'Content-Type' => 'application\u002Fjson' ),\n            'body'    => wp_json_encode( $payload ),\n            'timeout' => 10,\n        ) );\n\n        if ( is_wp_error( $response ) ) {\n            return false;\n        }\n\n        $code = wp_remote_retrieve_response_code( $response );\n        return $code >= 200 && $code \u003C 300;\n    }\n\n    \u002F**\n     * Test the channel connection with a sample message.\n     *\n     * @return true|WP_Error\n     *\u002F\n    public function test_connection() {\n        $settings    = $this->get_settings();\n        $webhook_url = $settings['webhook_url'] ?? '';\n\n        if ( empty( $webhook_url ) ) {\n            return new WP_Error( 'not_configured', __( 'Webhook URL is not set.', 'workflow-channel-{name}' ) );\n        }\n\n        $payload = array(\n            'text' => 'Test notification from VIP Workflows.',\n        );\n\n        $response = wp_remote_post( $webhook_url, array(\n            'headers' => array( 'Content-Type' => 'application\u002Fjson' ),\n            'body'    => wp_json_encode( $payload ),\n            'timeout' => 10,\n        ) );\n\n        if ( is_wp_error( $response ) ) {\n            return $response;\n        }\n\n        $code = wp_remote_retrieve_response_code( $response );\n        if ( $code \u003C 200 || $code >= 300 ) {\n            return new WP_Error(\n                'send_failed',\n                sprintf( __( 'Service returned HTTP %d.', 'workflow-channel-{name}' ), $code )\n            );\n        }\n\n        return true;\n    }\n\n    \u002F**\n     * Sanitize settings input.\n     *\n     * @param array $input Raw form input.\n     * @return array Sanitized settings.\n     *\u002F\n    public function sanitize_settings( array $input ): array {\n        return array(\n            'webhook_url' => esc_url_raw( $input['webhook_url'] ?? '' ),\n        );\n    }\n}\n```\n\n## Abstract Methods Reference\n\nThe `NotificationChannel` base class requires these abstract methods:\n\n| Method | Returns | Purpose |\n|--------|---------|---------|\n| `get_id()` | `string` | Unique channel ID (used for storage and API) |\n| `get_name()` | `string` | Human-readable display name |\n| `get_description()` | `string` | Short description |\n| `get_icon()` | `string` | Icon slug from the set in src\u002Fadmin\u002Fcomponents\u002Fideation\u002Fassistant-icon.js |\n| `is_configured()` | `bool` | Whether the channel is ready to send |\n| `send( Notification $notification )` | `bool` | Deliver a notification |\n| `test_connection()` | `true\\|WP_Error` | Verify the connection works |\n| `sanitize_settings( array $input )` | `array` | Sanitize form input |\n\nSettings are declared, not drawn. Override `get_settings_schema()` to return an array of field definitions; the base class puts it on the channel's REST payload via `to_array()`, and the React admin renders the form from it. There is no PHP-rendered settings form — a channel never emits settings markup of its own.\n\n## Built-in Base Class Helpers\n\nThese are provided by `NotificationChannel` and should not be overridden:\n- `$this->get_settings()` -- reads stored settings from `wp_options`\n- `$this->update_settings( $settings )` -- writes settings\n\n## Registration\n\nChannels register via the `vip_workflows_register_notification_channels` action, which receives a `$dispatcher` object. Call `$dispatcher->register_channel( new YourChannel() )`.\n\n## Testing\n\n1. Place the plugin directory alongside `vip-workflows\u002F`\n2. Activate it in WordPress admin\n3. Go to Integrations > Notification Channels to see the channel\n4. Configure the webhook URL and use \"Test Connection\" to verify\n5. Route an event to the channel on the `Routing` tab, then trigger a workflow transition to test delivery\n",{"data":43,"body":44},{"name":4,"description":6},{"type":45,"children":46},"root",[47,56,71,78,83,135,141,153,166,172,185,418,430,1641,1647,1659,1896,1917,1923,1935,1967,1973,2002,2008,2049],{"type":48,"tag":49,"props":50,"children":52},"element","h1",{"id":51},"create-a-vip-workflows-notification-channel",[53],{"type":54,"value":55},"text","Create a VIP Workflows Notification Channel",{"type":48,"tag":57,"props":58,"children":59},"p",{},[60,62,69],{"type":54,"value":61},"Notification channels deliver workflow event notifications (status changes, SLA breaches, publishing alerts) to external services. Each channel is a standalone WordPress plugin that extends the ",{"type":48,"tag":63,"props":64,"children":66},"code",{"className":65},[],[67],{"type":54,"value":68},"NotificationChannel",{"type":54,"value":70}," base class.",{"type":48,"tag":72,"props":73,"children":75},"h2",{"id":74},"requirements",[76],{"type":54,"value":77},"Requirements",{"type":48,"tag":57,"props":79,"children":80},{},[81],{"type":54,"value":82},"Before starting, gather from the user:",{"type":48,"tag":84,"props":85,"children":86},"ol",{},[87,99,115,125],{"type":48,"tag":88,"props":89,"children":90},"li",{},[91,97],{"type":48,"tag":92,"props":93,"children":94},"strong",{},[95],{"type":54,"value":96},"Destination service",{"type":54,"value":98}," -- e.g., Slack, Discord, Teams, Twilio SMS, PagerDuty",{"type":48,"tag":88,"props":100,"children":101},{},[102,107,109],{"type":48,"tag":92,"props":103,"children":104},{},[105],{"type":54,"value":106},"Plugin slug",{"type":54,"value":108}," -- e.g., ",{"type":48,"tag":63,"props":110,"children":112},{"className":111},[],[113],{"type":54,"value":114},"workflow-channel-slack",{"type":48,"tag":88,"props":116,"children":117},{},[118,123],{"type":48,"tag":92,"props":119,"children":120},{},[121],{"type":54,"value":122},"What credentials are needed?",{"type":54,"value":124}," -- webhook URL, API token, phone number, etc.",{"type":48,"tag":88,"props":126,"children":127},{},[128,133],{"type":48,"tag":92,"props":129,"children":130},{},[131],{"type":54,"value":132},"Does it support a test\u002Fping?",{"type":54,"value":134}," -- most webhook services do",{"type":48,"tag":72,"props":136,"children":138},{"id":137},"plugin-structure",[139],{"type":54,"value":140},"Plugin Structure",{"type":48,"tag":142,"props":143,"children":147},"pre",{"className":144,"code":146,"language":54},[145],"language-text","workflow-channel-{name}\u002F\n  workflow-channel-{name}.php       # Main plugin file (hooks + asset loading)\n  includes\u002F\n    class-{name}-channel.php        # Channel class extending NotificationChannel\n",[148],{"type":48,"tag":63,"props":149,"children":151},{"__ignoreMap":150},"",[152],{"type":54,"value":146},{"type":48,"tag":57,"props":154,"children":155},{},[156,158,164],{"type":54,"value":157},"The plugin directory lives alongside ",{"type":48,"tag":63,"props":159,"children":161},{"className":160},[],[162],{"type":54,"value":163},"vip-workflows\u002F",{"type":54,"value":165}," in the same parent directory.",{"type":48,"tag":72,"props":167,"children":169},{"id":168},"boilerplate",[170],{"type":54,"value":171},"Boilerplate",{"type":48,"tag":173,"props":174,"children":176},"h3",{"id":175},"main-plugin-file-workflow-channel-nameworkflow-channel-namephp",[177,179],{"type":54,"value":178},"Main plugin file: ",{"type":48,"tag":63,"props":180,"children":182},{"className":181},[],[183],{"type":54,"value":184},"workflow-channel-{name}\u002Fworkflow-channel-{name}.php",{"type":48,"tag":142,"props":186,"children":190},{"className":187,"code":188,"language":189,"meta":150,"style":150},"language-php shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003C?php\n\u002F**\n * Plugin Name: Workflow {Display Name} Channel\n * Description: Sends VIP Workflows notifications to {service}.\n * Version: 1.0.0\n * Requires Plugins: vip-workflows\n * Text Domain: workflow-channel-{name}\n *\n * @package WorkflowChannel{PascalName}\n *\u002F\n\ndeclare( strict_types=1 );\n\nnamespace WorkflowChannel{PascalName};\n\nif ( ! defined( 'ABSPATH' ) ) {\n    exit;\n}\n\ndefine( 'WORKFLOW_CHANNEL_{UPPER_NAME}_DIR', plugin_dir_path( __FILE__ ) );\n\nadd_action( 'vip_workflows_register_notification_channels', function( $dispatcher ) {\n    require_once WORKFLOW_CHANNEL_{UPPER_NAME}_DIR . 'includes\u002Fclass-{name}-channel.php';\n    $dispatcher->register_channel( new {PascalName}Channel() );\n} );\n","php",[191],{"type":48,"tag":63,"props":192,"children":193},{"__ignoreMap":150},[194,205,214,223,232,241,250,259,268,277,286,296,305,313,322,330,339,348,357,365,374,382,391,400,409],{"type":48,"tag":195,"props":196,"children":199},"span",{"class":197,"line":198},"line",1,[200],{"type":48,"tag":195,"props":201,"children":202},{},[203],{"type":54,"value":204},"\u003C?php\n",{"type":48,"tag":195,"props":206,"children":208},{"class":197,"line":207},2,[209],{"type":48,"tag":195,"props":210,"children":211},{},[212],{"type":54,"value":213},"\u002F**\n",{"type":48,"tag":195,"props":215,"children":217},{"class":197,"line":216},3,[218],{"type":48,"tag":195,"props":219,"children":220},{},[221],{"type":54,"value":222}," * Plugin Name: Workflow {Display Name} Channel\n",{"type":48,"tag":195,"props":224,"children":226},{"class":197,"line":225},4,[227],{"type":48,"tag":195,"props":228,"children":229},{},[230],{"type":54,"value":231}," * Description: Sends VIP Workflows notifications to {service}.\n",{"type":48,"tag":195,"props":233,"children":235},{"class":197,"line":234},5,[236],{"type":48,"tag":195,"props":237,"children":238},{},[239],{"type":54,"value":240}," * Version: 1.0.0\n",{"type":48,"tag":195,"props":242,"children":244},{"class":197,"line":243},6,[245],{"type":48,"tag":195,"props":246,"children":247},{},[248],{"type":54,"value":249}," * Requires Plugins: vip-workflows\n",{"type":48,"tag":195,"props":251,"children":253},{"class":197,"line":252},7,[254],{"type":48,"tag":195,"props":255,"children":256},{},[257],{"type":54,"value":258}," * Text Domain: workflow-channel-{name}\n",{"type":48,"tag":195,"props":260,"children":262},{"class":197,"line":261},8,[263],{"type":48,"tag":195,"props":264,"children":265},{},[266],{"type":54,"value":267}," *\n",{"type":48,"tag":195,"props":269,"children":271},{"class":197,"line":270},9,[272],{"type":48,"tag":195,"props":273,"children":274},{},[275],{"type":54,"value":276}," * @package WorkflowChannel{PascalName}\n",{"type":48,"tag":195,"props":278,"children":280},{"class":197,"line":279},10,[281],{"type":48,"tag":195,"props":282,"children":283},{},[284],{"type":54,"value":285}," *\u002F\n",{"type":48,"tag":195,"props":287,"children":289},{"class":197,"line":288},11,[290],{"type":48,"tag":195,"props":291,"children":293},{"emptyLinePlaceholder":292},true,[294],{"type":54,"value":295},"\n",{"type":48,"tag":195,"props":297,"children":299},{"class":197,"line":298},12,[300],{"type":48,"tag":195,"props":301,"children":302},{},[303],{"type":54,"value":304},"declare( strict_types=1 );\n",{"type":48,"tag":195,"props":306,"children":308},{"class":197,"line":307},13,[309],{"type":48,"tag":195,"props":310,"children":311},{"emptyLinePlaceholder":292},[312],{"type":54,"value":295},{"type":48,"tag":195,"props":314,"children":316},{"class":197,"line":315},14,[317],{"type":48,"tag":195,"props":318,"children":319},{},[320],{"type":54,"value":321},"namespace WorkflowChannel{PascalName};\n",{"type":48,"tag":195,"props":323,"children":325},{"class":197,"line":324},15,[326],{"type":48,"tag":195,"props":327,"children":328},{"emptyLinePlaceholder":292},[329],{"type":54,"value":295},{"type":48,"tag":195,"props":331,"children":333},{"class":197,"line":332},16,[334],{"type":48,"tag":195,"props":335,"children":336},{},[337],{"type":54,"value":338},"if ( ! defined( 'ABSPATH' ) ) {\n",{"type":48,"tag":195,"props":340,"children":342},{"class":197,"line":341},17,[343],{"type":48,"tag":195,"props":344,"children":345},{},[346],{"type":54,"value":347},"    exit;\n",{"type":48,"tag":195,"props":349,"children":351},{"class":197,"line":350},18,[352],{"type":48,"tag":195,"props":353,"children":354},{},[355],{"type":54,"value":356},"}\n",{"type":48,"tag":195,"props":358,"children":360},{"class":197,"line":359},19,[361],{"type":48,"tag":195,"props":362,"children":363},{"emptyLinePlaceholder":292},[364],{"type":54,"value":295},{"type":48,"tag":195,"props":366,"children":368},{"class":197,"line":367},20,[369],{"type":48,"tag":195,"props":370,"children":371},{},[372],{"type":54,"value":373},"define( 'WORKFLOW_CHANNEL_{UPPER_NAME}_DIR', plugin_dir_path( __FILE__ ) );\n",{"type":48,"tag":195,"props":375,"children":377},{"class":197,"line":376},21,[378],{"type":48,"tag":195,"props":379,"children":380},{"emptyLinePlaceholder":292},[381],{"type":54,"value":295},{"type":48,"tag":195,"props":383,"children":385},{"class":197,"line":384},22,[386],{"type":48,"tag":195,"props":387,"children":388},{},[389],{"type":54,"value":390},"add_action( 'vip_workflows_register_notification_channels', function( $dispatcher ) {\n",{"type":48,"tag":195,"props":392,"children":394},{"class":197,"line":393},23,[395],{"type":48,"tag":195,"props":396,"children":397},{},[398],{"type":54,"value":399},"    require_once WORKFLOW_CHANNEL_{UPPER_NAME}_DIR . 'includes\u002Fclass-{name}-channel.php';\n",{"type":48,"tag":195,"props":401,"children":403},{"class":197,"line":402},24,[404],{"type":48,"tag":195,"props":405,"children":406},{},[407],{"type":54,"value":408},"    $dispatcher->register_channel( new {PascalName}Channel() );\n",{"type":48,"tag":195,"props":410,"children":412},{"class":197,"line":411},25,[413],{"type":48,"tag":195,"props":414,"children":415},{},[416],{"type":54,"value":417},"} );\n",{"type":48,"tag":173,"props":419,"children":421},{"id":420},"channel-class-workflow-channel-nameincludesclass-name-channelphp",[422,424],{"type":54,"value":423},"Channel class: ",{"type":48,"tag":63,"props":425,"children":427},{"className":426},[],[428],{"type":54,"value":429},"workflow-channel-{name}\u002Fincludes\u002Fclass-{name}-channel.php",{"type":48,"tag":142,"props":431,"children":433},{"className":187,"code":432,"language":189,"meta":150,"style":150},"\u003C?php\ndeclare( strict_types=1 );\n\nnamespace WorkflowChannel{PascalName};\n\nuse VIPWorkflows\\Notifications\\NotificationChannel;\nuse VIPWorkflows\\Notifications\\Notification;\nuse WP_Error;\n\nclass {PascalName}Channel extends NotificationChannel {\n\n    public function get_id(): string {\n        return '{name}';\n    }\n\n    public function get_name(): string {\n        return __( '{Display Name}', 'workflow-channel-{name}' );\n    }\n\n    public function get_description(): string {\n        return __( 'Send notifications to {service}.', 'workflow-channel-{name}' );\n    }\n\n    public function get_icon(): string {\n        return 'search';\n    }\n\n    \u002F**\n     * Check if the channel has the required configuration to send.\n     *\u002F\n    public function is_configured(): bool {\n        $settings = $this->get_settings();\n        return ! empty( $settings['webhook_url'] );\n    }\n\n    \u002F**\n     * Define settings fields. Auto-rendered in the admin UI.\n     *\u002F\n    public function get_settings_schema(): array {\n        return array(\n            'webhook_url' => array(\n                'type'        => 'string',\n                'label'       => __( 'Webhook URL', 'workflow-channel-{name}' ),\n                'description' => __( 'The incoming webhook URL from {service}.', 'workflow-channel-{name}' ),\n                'required'    => true,\n            ),\n            \u002F\u002F Add more fields as needed:\n            \u002F\u002F 'channel' => array(\n            \u002F\u002F     'type'    => 'string',\n            \u002F\u002F     'label'   => __( 'Channel', 'workflow-channel-{name}' ),\n            \u002F\u002F     'default' => '#general',\n            \u002F\u002F ),\n        );\n    }\n\n    \u002F**\n     * Send a notification to the service.\n     *\n     * @param Notification $notification Contains ->get_subject(), ->get_body(),\n     *                                   ->get_post_id(), ->get_event_type(), etc.\n     * @return bool True on success.\n     *\u002F\n    public function send( Notification $notification ): bool {\n        $settings    = $this->get_settings();\n        $webhook_url = $settings['webhook_url'] ?? '';\n\n        if ( empty( $webhook_url ) ) {\n            return false;\n        }\n\n        \u002F\u002F Build the payload for your service.\n        \u002F\u002F Adapt this to match the service's expected format.\n        $payload = array(\n            'text' => sprintf(\n                \"**%s**\\n%s\",\n                $notification->get_subject(),\n                $notification->get_body()\n            ),\n        );\n\n        $response = wp_remote_post( $webhook_url, array(\n            'headers' => array( 'Content-Type' => 'application\u002Fjson' ),\n            'body'    => wp_json_encode( $payload ),\n            'timeout' => 10,\n        ) );\n\n        if ( is_wp_error( $response ) ) {\n            return false;\n        }\n\n        $code = wp_remote_retrieve_response_code( $response );\n        return $code >= 200 && $code \u003C 300;\n    }\n\n    \u002F**\n     * Test the channel connection with a sample message.\n     *\n     * @return true|WP_Error\n     *\u002F\n    public function test_connection() {\n        $settings    = $this->get_settings();\n        $webhook_url = $settings['webhook_url'] ?? '';\n\n        if ( empty( $webhook_url ) ) {\n            return new WP_Error( 'not_configured', __( 'Webhook URL is not set.', 'workflow-channel-{name}' ) );\n        }\n\n        $payload = array(\n            'text' => 'Test notification from VIP Workflows.',\n        );\n\n        $response = wp_remote_post( $webhook_url, array(\n            'headers' => array( 'Content-Type' => 'application\u002Fjson' ),\n            'body'    => wp_json_encode( $payload ),\n            'timeout' => 10,\n        ) );\n\n        if ( is_wp_error( $response ) ) {\n            return $response;\n        }\n\n        $code = wp_remote_retrieve_response_code( $response );\n        if ( $code \u003C 200 || $code >= 300 ) {\n            return new WP_Error(\n                'send_failed',\n                sprintf( __( 'Service returned HTTP %d.', 'workflow-channel-{name}' ), $code )\n            );\n        }\n\n        return true;\n    }\n\n    \u002F**\n     * Sanitize settings input.\n     *\n     * @param array $input Raw form input.\n     * @return array Sanitized settings.\n     *\u002F\n    public function sanitize_settings( array $input ): array {\n        return array(\n            'webhook_url' => esc_url_raw( $input['webhook_url'] ?? '' ),\n        );\n    }\n}\n",[434],{"type":48,"tag":63,"props":435,"children":436},{"__ignoreMap":150},[437,444,451,458,465,472,480,488,496,503,511,518,526,534,542,549,557,565,572,579,587,595,602,609,617,625,633,641,650,659,668,677,686,695,703,711,719,728,735,744,753,762,771,780,789,798,807,816,825,834,843,852,861,870,878,886,894,903,912,921,930,939,947,956,965,974,982,991,1000,1009,1017,1026,1035,1044,1053,1062,1071,1080,1088,1096,1104,1113,1122,1131,1140,1149,1157,1166,1174,1182,1190,1199,1208,1216,1224,1232,1241,1249,1258,1266,1275,1283,1291,1299,1307,1316,1324,1332,1340,1349,1357,1365,1373,1381,1389,1397,1405,1413,1421,1430,1438,1446,1454,1463,1472,1481,1490,1499,1507,1515,1524,1532,1540,1548,1557,1565,1574,1583,1591,1600,1608,1617,1625,1633],{"type":48,"tag":195,"props":438,"children":439},{"class":197,"line":198},[440],{"type":48,"tag":195,"props":441,"children":442},{},[443],{"type":54,"value":204},{"type":48,"tag":195,"props":445,"children":446},{"class":197,"line":207},[447],{"type":48,"tag":195,"props":448,"children":449},{},[450],{"type":54,"value":304},{"type":48,"tag":195,"props":452,"children":453},{"class":197,"line":216},[454],{"type":48,"tag":195,"props":455,"children":456},{"emptyLinePlaceholder":292},[457],{"type":54,"value":295},{"type":48,"tag":195,"props":459,"children":460},{"class":197,"line":225},[461],{"type":48,"tag":195,"props":462,"children":463},{},[464],{"type":54,"value":321},{"type":48,"tag":195,"props":466,"children":467},{"class":197,"line":234},[468],{"type":48,"tag":195,"props":469,"children":470},{"emptyLinePlaceholder":292},[471],{"type":54,"value":295},{"type":48,"tag":195,"props":473,"children":474},{"class":197,"line":243},[475],{"type":48,"tag":195,"props":476,"children":477},{},[478],{"type":54,"value":479},"use VIPWorkflows\\Notifications\\NotificationChannel;\n",{"type":48,"tag":195,"props":481,"children":482},{"class":197,"line":252},[483],{"type":48,"tag":195,"props":484,"children":485},{},[486],{"type":54,"value":487},"use VIPWorkflows\\Notifications\\Notification;\n",{"type":48,"tag":195,"props":489,"children":490},{"class":197,"line":261},[491],{"type":48,"tag":195,"props":492,"children":493},{},[494],{"type":54,"value":495},"use WP_Error;\n",{"type":48,"tag":195,"props":497,"children":498},{"class":197,"line":270},[499],{"type":48,"tag":195,"props":500,"children":501},{"emptyLinePlaceholder":292},[502],{"type":54,"value":295},{"type":48,"tag":195,"props":504,"children":505},{"class":197,"line":279},[506],{"type":48,"tag":195,"props":507,"children":508},{},[509],{"type":54,"value":510},"class {PascalName}Channel extends NotificationChannel {\n",{"type":48,"tag":195,"props":512,"children":513},{"class":197,"line":288},[514],{"type":48,"tag":195,"props":515,"children":516},{"emptyLinePlaceholder":292},[517],{"type":54,"value":295},{"type":48,"tag":195,"props":519,"children":520},{"class":197,"line":298},[521],{"type":48,"tag":195,"props":522,"children":523},{},[524],{"type":54,"value":525},"    public function get_id(): string {\n",{"type":48,"tag":195,"props":527,"children":528},{"class":197,"line":307},[529],{"type":48,"tag":195,"props":530,"children":531},{},[532],{"type":54,"value":533},"        return '{name}';\n",{"type":48,"tag":195,"props":535,"children":536},{"class":197,"line":315},[537],{"type":48,"tag":195,"props":538,"children":539},{},[540],{"type":54,"value":541},"    }\n",{"type":48,"tag":195,"props":543,"children":544},{"class":197,"line":324},[545],{"type":48,"tag":195,"props":546,"children":547},{"emptyLinePlaceholder":292},[548],{"type":54,"value":295},{"type":48,"tag":195,"props":550,"children":551},{"class":197,"line":332},[552],{"type":48,"tag":195,"props":553,"children":554},{},[555],{"type":54,"value":556},"    public function get_name(): string {\n",{"type":48,"tag":195,"props":558,"children":559},{"class":197,"line":341},[560],{"type":48,"tag":195,"props":561,"children":562},{},[563],{"type":54,"value":564},"        return __( '{Display Name}', 'workflow-channel-{name}' );\n",{"type":48,"tag":195,"props":566,"children":567},{"class":197,"line":350},[568],{"type":48,"tag":195,"props":569,"children":570},{},[571],{"type":54,"value":541},{"type":48,"tag":195,"props":573,"children":574},{"class":197,"line":359},[575],{"type":48,"tag":195,"props":576,"children":577},{"emptyLinePlaceholder":292},[578],{"type":54,"value":295},{"type":48,"tag":195,"props":580,"children":581},{"class":197,"line":367},[582],{"type":48,"tag":195,"props":583,"children":584},{},[585],{"type":54,"value":586},"    public function get_description(): string {\n",{"type":48,"tag":195,"props":588,"children":589},{"class":197,"line":376},[590],{"type":48,"tag":195,"props":591,"children":592},{},[593],{"type":54,"value":594},"        return __( 'Send notifications to {service}.', 'workflow-channel-{name}' );\n",{"type":48,"tag":195,"props":596,"children":597},{"class":197,"line":384},[598],{"type":48,"tag":195,"props":599,"children":600},{},[601],{"type":54,"value":541},{"type":48,"tag":195,"props":603,"children":604},{"class":197,"line":393},[605],{"type":48,"tag":195,"props":606,"children":607},{"emptyLinePlaceholder":292},[608],{"type":54,"value":295},{"type":48,"tag":195,"props":610,"children":611},{"class":197,"line":402},[612],{"type":48,"tag":195,"props":613,"children":614},{},[615],{"type":54,"value":616},"    public function get_icon(): string {\n",{"type":48,"tag":195,"props":618,"children":619},{"class":197,"line":411},[620],{"type":48,"tag":195,"props":621,"children":622},{},[623],{"type":54,"value":624},"        return 'search';\n",{"type":48,"tag":195,"props":626,"children":628},{"class":197,"line":627},26,[629],{"type":48,"tag":195,"props":630,"children":631},{},[632],{"type":54,"value":541},{"type":48,"tag":195,"props":634,"children":636},{"class":197,"line":635},27,[637],{"type":48,"tag":195,"props":638,"children":639},{"emptyLinePlaceholder":292},[640],{"type":54,"value":295},{"type":48,"tag":195,"props":642,"children":644},{"class":197,"line":643},28,[645],{"type":48,"tag":195,"props":646,"children":647},{},[648],{"type":54,"value":649},"    \u002F**\n",{"type":48,"tag":195,"props":651,"children":653},{"class":197,"line":652},29,[654],{"type":48,"tag":195,"props":655,"children":656},{},[657],{"type":54,"value":658},"     * Check if the channel has the required configuration to send.\n",{"type":48,"tag":195,"props":660,"children":662},{"class":197,"line":661},30,[663],{"type":48,"tag":195,"props":664,"children":665},{},[666],{"type":54,"value":667},"     *\u002F\n",{"type":48,"tag":195,"props":669,"children":671},{"class":197,"line":670},31,[672],{"type":48,"tag":195,"props":673,"children":674},{},[675],{"type":54,"value":676},"    public function is_configured(): bool {\n",{"type":48,"tag":195,"props":678,"children":680},{"class":197,"line":679},32,[681],{"type":48,"tag":195,"props":682,"children":683},{},[684],{"type":54,"value":685},"        $settings = $this->get_settings();\n",{"type":48,"tag":195,"props":687,"children":689},{"class":197,"line":688},33,[690],{"type":48,"tag":195,"props":691,"children":692},{},[693],{"type":54,"value":694},"        return ! empty( $settings['webhook_url'] );\n",{"type":48,"tag":195,"props":696,"children":698},{"class":197,"line":697},34,[699],{"type":48,"tag":195,"props":700,"children":701},{},[702],{"type":54,"value":541},{"type":48,"tag":195,"props":704,"children":706},{"class":197,"line":705},35,[707],{"type":48,"tag":195,"props":708,"children":709},{"emptyLinePlaceholder":292},[710],{"type":54,"value":295},{"type":48,"tag":195,"props":712,"children":714},{"class":197,"line":713},36,[715],{"type":48,"tag":195,"props":716,"children":717},{},[718],{"type":54,"value":649},{"type":48,"tag":195,"props":720,"children":722},{"class":197,"line":721},37,[723],{"type":48,"tag":195,"props":724,"children":725},{},[726],{"type":54,"value":727},"     * Define settings fields. Auto-rendered in the admin UI.\n",{"type":48,"tag":195,"props":729,"children":730},{"class":197,"line":32},[731],{"type":48,"tag":195,"props":732,"children":733},{},[734],{"type":54,"value":667},{"type":48,"tag":195,"props":736,"children":738},{"class":197,"line":737},39,[739],{"type":48,"tag":195,"props":740,"children":741},{},[742],{"type":54,"value":743},"    public function get_settings_schema(): array {\n",{"type":48,"tag":195,"props":745,"children":747},{"class":197,"line":746},40,[748],{"type":48,"tag":195,"props":749,"children":750},{},[751],{"type":54,"value":752},"        return array(\n",{"type":48,"tag":195,"props":754,"children":756},{"class":197,"line":755},41,[757],{"type":48,"tag":195,"props":758,"children":759},{},[760],{"type":54,"value":761},"            'webhook_url' => array(\n",{"type":48,"tag":195,"props":763,"children":765},{"class":197,"line":764},42,[766],{"type":48,"tag":195,"props":767,"children":768},{},[769],{"type":54,"value":770},"                'type'        => 'string',\n",{"type":48,"tag":195,"props":772,"children":774},{"class":197,"line":773},43,[775],{"type":48,"tag":195,"props":776,"children":777},{},[778],{"type":54,"value":779},"                'label'       => __( 'Webhook URL', 'workflow-channel-{name}' ),\n",{"type":48,"tag":195,"props":781,"children":783},{"class":197,"line":782},44,[784],{"type":48,"tag":195,"props":785,"children":786},{},[787],{"type":54,"value":788},"                'description' => __( 'The incoming webhook URL from {service}.', 'workflow-channel-{name}' ),\n",{"type":48,"tag":195,"props":790,"children":792},{"class":197,"line":791},45,[793],{"type":48,"tag":195,"props":794,"children":795},{},[796],{"type":54,"value":797},"                'required'    => true,\n",{"type":48,"tag":195,"props":799,"children":801},{"class":197,"line":800},46,[802],{"type":48,"tag":195,"props":803,"children":804},{},[805],{"type":54,"value":806},"            ),\n",{"type":48,"tag":195,"props":808,"children":810},{"class":197,"line":809},47,[811],{"type":48,"tag":195,"props":812,"children":813},{},[814],{"type":54,"value":815},"            \u002F\u002F Add more fields as needed:\n",{"type":48,"tag":195,"props":817,"children":819},{"class":197,"line":818},48,[820],{"type":48,"tag":195,"props":821,"children":822},{},[823],{"type":54,"value":824},"            \u002F\u002F 'channel' => array(\n",{"type":48,"tag":195,"props":826,"children":828},{"class":197,"line":827},49,[829],{"type":48,"tag":195,"props":830,"children":831},{},[832],{"type":54,"value":833},"            \u002F\u002F     'type'    => 'string',\n",{"type":48,"tag":195,"props":835,"children":837},{"class":197,"line":836},50,[838],{"type":48,"tag":195,"props":839,"children":840},{},[841],{"type":54,"value":842},"            \u002F\u002F     'label'   => __( 'Channel', 'workflow-channel-{name}' ),\n",{"type":48,"tag":195,"props":844,"children":846},{"class":197,"line":845},51,[847],{"type":48,"tag":195,"props":848,"children":849},{},[850],{"type":54,"value":851},"            \u002F\u002F     'default' => '#general',\n",{"type":48,"tag":195,"props":853,"children":855},{"class":197,"line":854},52,[856],{"type":48,"tag":195,"props":857,"children":858},{},[859],{"type":54,"value":860},"            \u002F\u002F ),\n",{"type":48,"tag":195,"props":862,"children":864},{"class":197,"line":863},53,[865],{"type":48,"tag":195,"props":866,"children":867},{},[868],{"type":54,"value":869},"        );\n",{"type":48,"tag":195,"props":871,"children":873},{"class":197,"line":872},54,[874],{"type":48,"tag":195,"props":875,"children":876},{},[877],{"type":54,"value":541},{"type":48,"tag":195,"props":879,"children":881},{"class":197,"line":880},55,[882],{"type":48,"tag":195,"props":883,"children":884},{"emptyLinePlaceholder":292},[885],{"type":54,"value":295},{"type":48,"tag":195,"props":887,"children":889},{"class":197,"line":888},56,[890],{"type":48,"tag":195,"props":891,"children":892},{},[893],{"type":54,"value":649},{"type":48,"tag":195,"props":895,"children":897},{"class":197,"line":896},57,[898],{"type":48,"tag":195,"props":899,"children":900},{},[901],{"type":54,"value":902},"     * Send a notification to the service.\n",{"type":48,"tag":195,"props":904,"children":906},{"class":197,"line":905},58,[907],{"type":48,"tag":195,"props":908,"children":909},{},[910],{"type":54,"value":911},"     *\n",{"type":48,"tag":195,"props":913,"children":915},{"class":197,"line":914},59,[916],{"type":48,"tag":195,"props":917,"children":918},{},[919],{"type":54,"value":920},"     * @param Notification $notification Contains ->get_subject(), ->get_body(),\n",{"type":48,"tag":195,"props":922,"children":924},{"class":197,"line":923},60,[925],{"type":48,"tag":195,"props":926,"children":927},{},[928],{"type":54,"value":929},"     *                                   ->get_post_id(), ->get_event_type(), etc.\n",{"type":48,"tag":195,"props":931,"children":933},{"class":197,"line":932},61,[934],{"type":48,"tag":195,"props":935,"children":936},{},[937],{"type":54,"value":938},"     * @return bool True on success.\n",{"type":48,"tag":195,"props":940,"children":942},{"class":197,"line":941},62,[943],{"type":48,"tag":195,"props":944,"children":945},{},[946],{"type":54,"value":667},{"type":48,"tag":195,"props":948,"children":950},{"class":197,"line":949},63,[951],{"type":48,"tag":195,"props":952,"children":953},{},[954],{"type":54,"value":955},"    public function send( Notification $notification ): bool {\n",{"type":48,"tag":195,"props":957,"children":959},{"class":197,"line":958},64,[960],{"type":48,"tag":195,"props":961,"children":962},{},[963],{"type":54,"value":964},"        $settings    = $this->get_settings();\n",{"type":48,"tag":195,"props":966,"children":968},{"class":197,"line":967},65,[969],{"type":48,"tag":195,"props":970,"children":971},{},[972],{"type":54,"value":973},"        $webhook_url = $settings['webhook_url'] ?? '';\n",{"type":48,"tag":195,"props":975,"children":977},{"class":197,"line":976},66,[978],{"type":48,"tag":195,"props":979,"children":980},{"emptyLinePlaceholder":292},[981],{"type":54,"value":295},{"type":48,"tag":195,"props":983,"children":985},{"class":197,"line":984},67,[986],{"type":48,"tag":195,"props":987,"children":988},{},[989],{"type":54,"value":990},"        if ( empty( $webhook_url ) ) {\n",{"type":48,"tag":195,"props":992,"children":994},{"class":197,"line":993},68,[995],{"type":48,"tag":195,"props":996,"children":997},{},[998],{"type":54,"value":999},"            return false;\n",{"type":48,"tag":195,"props":1001,"children":1003},{"class":197,"line":1002},69,[1004],{"type":48,"tag":195,"props":1005,"children":1006},{},[1007],{"type":54,"value":1008},"        }\n",{"type":48,"tag":195,"props":1010,"children":1012},{"class":197,"line":1011},70,[1013],{"type":48,"tag":195,"props":1014,"children":1015},{"emptyLinePlaceholder":292},[1016],{"type":54,"value":295},{"type":48,"tag":195,"props":1018,"children":1020},{"class":197,"line":1019},71,[1021],{"type":48,"tag":195,"props":1022,"children":1023},{},[1024],{"type":54,"value":1025},"        \u002F\u002F Build the payload for your service.\n",{"type":48,"tag":195,"props":1027,"children":1029},{"class":197,"line":1028},72,[1030],{"type":48,"tag":195,"props":1031,"children":1032},{},[1033],{"type":54,"value":1034},"        \u002F\u002F Adapt this to match the service's expected format.\n",{"type":48,"tag":195,"props":1036,"children":1038},{"class":197,"line":1037},73,[1039],{"type":48,"tag":195,"props":1040,"children":1041},{},[1042],{"type":54,"value":1043},"        $payload = array(\n",{"type":48,"tag":195,"props":1045,"children":1047},{"class":197,"line":1046},74,[1048],{"type":48,"tag":195,"props":1049,"children":1050},{},[1051],{"type":54,"value":1052},"            'text' => sprintf(\n",{"type":48,"tag":195,"props":1054,"children":1056},{"class":197,"line":1055},75,[1057],{"type":48,"tag":195,"props":1058,"children":1059},{},[1060],{"type":54,"value":1061},"                \"**%s**\\n%s\",\n",{"type":48,"tag":195,"props":1063,"children":1065},{"class":197,"line":1064},76,[1066],{"type":48,"tag":195,"props":1067,"children":1068},{},[1069],{"type":54,"value":1070},"                $notification->get_subject(),\n",{"type":48,"tag":195,"props":1072,"children":1074},{"class":197,"line":1073},77,[1075],{"type":48,"tag":195,"props":1076,"children":1077},{},[1078],{"type":54,"value":1079},"                $notification->get_body()\n",{"type":48,"tag":195,"props":1081,"children":1083},{"class":197,"line":1082},78,[1084],{"type":48,"tag":195,"props":1085,"children":1086},{},[1087],{"type":54,"value":806},{"type":48,"tag":195,"props":1089,"children":1091},{"class":197,"line":1090},79,[1092],{"type":48,"tag":195,"props":1093,"children":1094},{},[1095],{"type":54,"value":869},{"type":48,"tag":195,"props":1097,"children":1099},{"class":197,"line":1098},80,[1100],{"type":48,"tag":195,"props":1101,"children":1102},{"emptyLinePlaceholder":292},[1103],{"type":54,"value":295},{"type":48,"tag":195,"props":1105,"children":1107},{"class":197,"line":1106},81,[1108],{"type":48,"tag":195,"props":1109,"children":1110},{},[1111],{"type":54,"value":1112},"        $response = wp_remote_post( $webhook_url, array(\n",{"type":48,"tag":195,"props":1114,"children":1116},{"class":197,"line":1115},82,[1117],{"type":48,"tag":195,"props":1118,"children":1119},{},[1120],{"type":54,"value":1121},"            'headers' => array( 'Content-Type' => 'application\u002Fjson' ),\n",{"type":48,"tag":195,"props":1123,"children":1125},{"class":197,"line":1124},83,[1126],{"type":48,"tag":195,"props":1127,"children":1128},{},[1129],{"type":54,"value":1130},"            'body'    => wp_json_encode( $payload ),\n",{"type":48,"tag":195,"props":1132,"children":1134},{"class":197,"line":1133},84,[1135],{"type":48,"tag":195,"props":1136,"children":1137},{},[1138],{"type":54,"value":1139},"            'timeout' => 10,\n",{"type":48,"tag":195,"props":1141,"children":1143},{"class":197,"line":1142},85,[1144],{"type":48,"tag":195,"props":1145,"children":1146},{},[1147],{"type":54,"value":1148},"        ) );\n",{"type":48,"tag":195,"props":1150,"children":1152},{"class":197,"line":1151},86,[1153],{"type":48,"tag":195,"props":1154,"children":1155},{"emptyLinePlaceholder":292},[1156],{"type":54,"value":295},{"type":48,"tag":195,"props":1158,"children":1160},{"class":197,"line":1159},87,[1161],{"type":48,"tag":195,"props":1162,"children":1163},{},[1164],{"type":54,"value":1165},"        if ( is_wp_error( $response ) ) {\n",{"type":48,"tag":195,"props":1167,"children":1169},{"class":197,"line":1168},88,[1170],{"type":48,"tag":195,"props":1171,"children":1172},{},[1173],{"type":54,"value":999},{"type":48,"tag":195,"props":1175,"children":1177},{"class":197,"line":1176},89,[1178],{"type":48,"tag":195,"props":1179,"children":1180},{},[1181],{"type":54,"value":1008},{"type":48,"tag":195,"props":1183,"children":1185},{"class":197,"line":1184},90,[1186],{"type":48,"tag":195,"props":1187,"children":1188},{"emptyLinePlaceholder":292},[1189],{"type":54,"value":295},{"type":48,"tag":195,"props":1191,"children":1193},{"class":197,"line":1192},91,[1194],{"type":48,"tag":195,"props":1195,"children":1196},{},[1197],{"type":54,"value":1198},"        $code = wp_remote_retrieve_response_code( $response );\n",{"type":48,"tag":195,"props":1200,"children":1202},{"class":197,"line":1201},92,[1203],{"type":48,"tag":195,"props":1204,"children":1205},{},[1206],{"type":54,"value":1207},"        return $code >= 200 && $code \u003C 300;\n",{"type":48,"tag":195,"props":1209,"children":1211},{"class":197,"line":1210},93,[1212],{"type":48,"tag":195,"props":1213,"children":1214},{},[1215],{"type":54,"value":541},{"type":48,"tag":195,"props":1217,"children":1219},{"class":197,"line":1218},94,[1220],{"type":48,"tag":195,"props":1221,"children":1222},{"emptyLinePlaceholder":292},[1223],{"type":54,"value":295},{"type":48,"tag":195,"props":1225,"children":1227},{"class":197,"line":1226},95,[1228],{"type":48,"tag":195,"props":1229,"children":1230},{},[1231],{"type":54,"value":649},{"type":48,"tag":195,"props":1233,"children":1235},{"class":197,"line":1234},96,[1236],{"type":48,"tag":195,"props":1237,"children":1238},{},[1239],{"type":54,"value":1240},"     * Test the channel connection with a sample message.\n",{"type":48,"tag":195,"props":1242,"children":1244},{"class":197,"line":1243},97,[1245],{"type":48,"tag":195,"props":1246,"children":1247},{},[1248],{"type":54,"value":911},{"type":48,"tag":195,"props":1250,"children":1252},{"class":197,"line":1251},98,[1253],{"type":48,"tag":195,"props":1254,"children":1255},{},[1256],{"type":54,"value":1257},"     * @return true|WP_Error\n",{"type":48,"tag":195,"props":1259,"children":1261},{"class":197,"line":1260},99,[1262],{"type":48,"tag":195,"props":1263,"children":1264},{},[1265],{"type":54,"value":667},{"type":48,"tag":195,"props":1267,"children":1269},{"class":197,"line":1268},100,[1270],{"type":48,"tag":195,"props":1271,"children":1272},{},[1273],{"type":54,"value":1274},"    public function test_connection() {\n",{"type":48,"tag":195,"props":1276,"children":1278},{"class":197,"line":1277},101,[1279],{"type":48,"tag":195,"props":1280,"children":1281},{},[1282],{"type":54,"value":964},{"type":48,"tag":195,"props":1284,"children":1286},{"class":197,"line":1285},102,[1287],{"type":48,"tag":195,"props":1288,"children":1289},{},[1290],{"type":54,"value":973},{"type":48,"tag":195,"props":1292,"children":1294},{"class":197,"line":1293},103,[1295],{"type":48,"tag":195,"props":1296,"children":1297},{"emptyLinePlaceholder":292},[1298],{"type":54,"value":295},{"type":48,"tag":195,"props":1300,"children":1302},{"class":197,"line":1301},104,[1303],{"type":48,"tag":195,"props":1304,"children":1305},{},[1306],{"type":54,"value":990},{"type":48,"tag":195,"props":1308,"children":1310},{"class":197,"line":1309},105,[1311],{"type":48,"tag":195,"props":1312,"children":1313},{},[1314],{"type":54,"value":1315},"            return new WP_Error( 'not_configured', __( 'Webhook URL is not set.', 'workflow-channel-{name}' ) );\n",{"type":48,"tag":195,"props":1317,"children":1319},{"class":197,"line":1318},106,[1320],{"type":48,"tag":195,"props":1321,"children":1322},{},[1323],{"type":54,"value":1008},{"type":48,"tag":195,"props":1325,"children":1327},{"class":197,"line":1326},107,[1328],{"type":48,"tag":195,"props":1329,"children":1330},{"emptyLinePlaceholder":292},[1331],{"type":54,"value":295},{"type":48,"tag":195,"props":1333,"children":1335},{"class":197,"line":1334},108,[1336],{"type":48,"tag":195,"props":1337,"children":1338},{},[1339],{"type":54,"value":1043},{"type":48,"tag":195,"props":1341,"children":1343},{"class":197,"line":1342},109,[1344],{"type":48,"tag":195,"props":1345,"children":1346},{},[1347],{"type":54,"value":1348},"            'text' => 'Test notification from VIP Workflows.',\n",{"type":48,"tag":195,"props":1350,"children":1352},{"class":197,"line":1351},110,[1353],{"type":48,"tag":195,"props":1354,"children":1355},{},[1356],{"type":54,"value":869},{"type":48,"tag":195,"props":1358,"children":1360},{"class":197,"line":1359},111,[1361],{"type":48,"tag":195,"props":1362,"children":1363},{"emptyLinePlaceholder":292},[1364],{"type":54,"value":295},{"type":48,"tag":195,"props":1366,"children":1368},{"class":197,"line":1367},112,[1369],{"type":48,"tag":195,"props":1370,"children":1371},{},[1372],{"type":54,"value":1112},{"type":48,"tag":195,"props":1374,"children":1376},{"class":197,"line":1375},113,[1377],{"type":48,"tag":195,"props":1378,"children":1379},{},[1380],{"type":54,"value":1121},{"type":48,"tag":195,"props":1382,"children":1384},{"class":197,"line":1383},114,[1385],{"type":48,"tag":195,"props":1386,"children":1387},{},[1388],{"type":54,"value":1130},{"type":48,"tag":195,"props":1390,"children":1392},{"class":197,"line":1391},115,[1393],{"type":48,"tag":195,"props":1394,"children":1395},{},[1396],{"type":54,"value":1139},{"type":48,"tag":195,"props":1398,"children":1400},{"class":197,"line":1399},116,[1401],{"type":48,"tag":195,"props":1402,"children":1403},{},[1404],{"type":54,"value":1148},{"type":48,"tag":195,"props":1406,"children":1408},{"class":197,"line":1407},117,[1409],{"type":48,"tag":195,"props":1410,"children":1411},{"emptyLinePlaceholder":292},[1412],{"type":54,"value":295},{"type":48,"tag":195,"props":1414,"children":1416},{"class":197,"line":1415},118,[1417],{"type":48,"tag":195,"props":1418,"children":1419},{},[1420],{"type":54,"value":1165},{"type":48,"tag":195,"props":1422,"children":1424},{"class":197,"line":1423},119,[1425],{"type":48,"tag":195,"props":1426,"children":1427},{},[1428],{"type":54,"value":1429},"            return $response;\n",{"type":48,"tag":195,"props":1431,"children":1433},{"class":197,"line":1432},120,[1434],{"type":48,"tag":195,"props":1435,"children":1436},{},[1437],{"type":54,"value":1008},{"type":48,"tag":195,"props":1439,"children":1441},{"class":197,"line":1440},121,[1442],{"type":48,"tag":195,"props":1443,"children":1444},{"emptyLinePlaceholder":292},[1445],{"type":54,"value":295},{"type":48,"tag":195,"props":1447,"children":1449},{"class":197,"line":1448},122,[1450],{"type":48,"tag":195,"props":1451,"children":1452},{},[1453],{"type":54,"value":1198},{"type":48,"tag":195,"props":1455,"children":1457},{"class":197,"line":1456},123,[1458],{"type":48,"tag":195,"props":1459,"children":1460},{},[1461],{"type":54,"value":1462},"        if ( $code \u003C 200 || $code >= 300 ) {\n",{"type":48,"tag":195,"props":1464,"children":1466},{"class":197,"line":1465},124,[1467],{"type":48,"tag":195,"props":1468,"children":1469},{},[1470],{"type":54,"value":1471},"            return new WP_Error(\n",{"type":48,"tag":195,"props":1473,"children":1475},{"class":197,"line":1474},125,[1476],{"type":48,"tag":195,"props":1477,"children":1478},{},[1479],{"type":54,"value":1480},"                'send_failed',\n",{"type":48,"tag":195,"props":1482,"children":1484},{"class":197,"line":1483},126,[1485],{"type":48,"tag":195,"props":1486,"children":1487},{},[1488],{"type":54,"value":1489},"                sprintf( __( 'Service returned HTTP %d.', 'workflow-channel-{name}' ), $code )\n",{"type":48,"tag":195,"props":1491,"children":1493},{"class":197,"line":1492},127,[1494],{"type":48,"tag":195,"props":1495,"children":1496},{},[1497],{"type":54,"value":1498},"            );\n",{"type":48,"tag":195,"props":1500,"children":1502},{"class":197,"line":1501},128,[1503],{"type":48,"tag":195,"props":1504,"children":1505},{},[1506],{"type":54,"value":1008},{"type":48,"tag":195,"props":1508,"children":1510},{"class":197,"line":1509},129,[1511],{"type":48,"tag":195,"props":1512,"children":1513},{"emptyLinePlaceholder":292},[1514],{"type":54,"value":295},{"type":48,"tag":195,"props":1516,"children":1518},{"class":197,"line":1517},130,[1519],{"type":48,"tag":195,"props":1520,"children":1521},{},[1522],{"type":54,"value":1523},"        return true;\n",{"type":48,"tag":195,"props":1525,"children":1527},{"class":197,"line":1526},131,[1528],{"type":48,"tag":195,"props":1529,"children":1530},{},[1531],{"type":54,"value":541},{"type":48,"tag":195,"props":1533,"children":1535},{"class":197,"line":1534},132,[1536],{"type":48,"tag":195,"props":1537,"children":1538},{"emptyLinePlaceholder":292},[1539],{"type":54,"value":295},{"type":48,"tag":195,"props":1541,"children":1543},{"class":197,"line":1542},133,[1544],{"type":48,"tag":195,"props":1545,"children":1546},{},[1547],{"type":54,"value":649},{"type":48,"tag":195,"props":1549,"children":1551},{"class":197,"line":1550},134,[1552],{"type":48,"tag":195,"props":1553,"children":1554},{},[1555],{"type":54,"value":1556},"     * Sanitize settings input.\n",{"type":48,"tag":195,"props":1558,"children":1560},{"class":197,"line":1559},135,[1561],{"type":48,"tag":195,"props":1562,"children":1563},{},[1564],{"type":54,"value":911},{"type":48,"tag":195,"props":1566,"children":1568},{"class":197,"line":1567},136,[1569],{"type":48,"tag":195,"props":1570,"children":1571},{},[1572],{"type":54,"value":1573},"     * @param array $input Raw form input.\n",{"type":48,"tag":195,"props":1575,"children":1577},{"class":197,"line":1576},137,[1578],{"type":48,"tag":195,"props":1579,"children":1580},{},[1581],{"type":54,"value":1582},"     * @return array Sanitized settings.\n",{"type":48,"tag":195,"props":1584,"children":1586},{"class":197,"line":1585},138,[1587],{"type":48,"tag":195,"props":1588,"children":1589},{},[1590],{"type":54,"value":667},{"type":48,"tag":195,"props":1592,"children":1594},{"class":197,"line":1593},139,[1595],{"type":48,"tag":195,"props":1596,"children":1597},{},[1598],{"type":54,"value":1599},"    public function sanitize_settings( array $input ): array {\n",{"type":48,"tag":195,"props":1601,"children":1603},{"class":197,"line":1602},140,[1604],{"type":48,"tag":195,"props":1605,"children":1606},{},[1607],{"type":54,"value":752},{"type":48,"tag":195,"props":1609,"children":1611},{"class":197,"line":1610},141,[1612],{"type":48,"tag":195,"props":1613,"children":1614},{},[1615],{"type":54,"value":1616},"            'webhook_url' => esc_url_raw( $input['webhook_url'] ?? '' ),\n",{"type":48,"tag":195,"props":1618,"children":1620},{"class":197,"line":1619},142,[1621],{"type":48,"tag":195,"props":1622,"children":1623},{},[1624],{"type":54,"value":869},{"type":48,"tag":195,"props":1626,"children":1628},{"class":197,"line":1627},143,[1629],{"type":48,"tag":195,"props":1630,"children":1631},{},[1632],{"type":54,"value":541},{"type":48,"tag":195,"props":1634,"children":1636},{"class":197,"line":1635},144,[1637],{"type":48,"tag":195,"props":1638,"children":1639},{},[1640],{"type":54,"value":356},{"type":48,"tag":72,"props":1642,"children":1644},{"id":1643},"abstract-methods-reference",[1645],{"type":54,"value":1646},"Abstract Methods Reference",{"type":48,"tag":57,"props":1648,"children":1649},{},[1650,1652,1657],{"type":54,"value":1651},"The ",{"type":48,"tag":63,"props":1653,"children":1655},{"className":1654},[],[1656],{"type":54,"value":68},{"type":54,"value":1658}," base class requires these abstract methods:",{"type":48,"tag":1660,"props":1661,"children":1662},"table",{},[1663,1687],{"type":48,"tag":1664,"props":1665,"children":1666},"thead",{},[1667],{"type":48,"tag":1668,"props":1669,"children":1670},"tr",{},[1671,1677,1682],{"type":48,"tag":1672,"props":1673,"children":1674},"th",{},[1675],{"type":54,"value":1676},"Method",{"type":48,"tag":1672,"props":1678,"children":1679},{},[1680],{"type":54,"value":1681},"Returns",{"type":48,"tag":1672,"props":1683,"children":1684},{},[1685],{"type":54,"value":1686},"Purpose",{"type":48,"tag":1688,"props":1689,"children":1690},"tbody",{},[1691,1718,1743,1768,1793,1819,1844,1870],{"type":48,"tag":1668,"props":1692,"children":1693},{},[1694,1704,1713],{"type":48,"tag":1695,"props":1696,"children":1697},"td",{},[1698],{"type":48,"tag":63,"props":1699,"children":1701},{"className":1700},[],[1702],{"type":54,"value":1703},"get_id()",{"type":48,"tag":1695,"props":1705,"children":1706},{},[1707],{"type":48,"tag":63,"props":1708,"children":1710},{"className":1709},[],[1711],{"type":54,"value":1712},"string",{"type":48,"tag":1695,"props":1714,"children":1715},{},[1716],{"type":54,"value":1717},"Unique channel ID (used for storage and API)",{"type":48,"tag":1668,"props":1719,"children":1720},{},[1721,1730,1738],{"type":48,"tag":1695,"props":1722,"children":1723},{},[1724],{"type":48,"tag":63,"props":1725,"children":1727},{"className":1726},[],[1728],{"type":54,"value":1729},"get_name()",{"type":48,"tag":1695,"props":1731,"children":1732},{},[1733],{"type":48,"tag":63,"props":1734,"children":1736},{"className":1735},[],[1737],{"type":54,"value":1712},{"type":48,"tag":1695,"props":1739,"children":1740},{},[1741],{"type":54,"value":1742},"Human-readable display name",{"type":48,"tag":1668,"props":1744,"children":1745},{},[1746,1755,1763],{"type":48,"tag":1695,"props":1747,"children":1748},{},[1749],{"type":48,"tag":63,"props":1750,"children":1752},{"className":1751},[],[1753],{"type":54,"value":1754},"get_description()",{"type":48,"tag":1695,"props":1756,"children":1757},{},[1758],{"type":48,"tag":63,"props":1759,"children":1761},{"className":1760},[],[1762],{"type":54,"value":1712},{"type":48,"tag":1695,"props":1764,"children":1765},{},[1766],{"type":54,"value":1767},"Short description",{"type":48,"tag":1668,"props":1769,"children":1770},{},[1771,1780,1788],{"type":48,"tag":1695,"props":1772,"children":1773},{},[1774],{"type":48,"tag":63,"props":1775,"children":1777},{"className":1776},[],[1778],{"type":54,"value":1779},"get_icon()",{"type":48,"tag":1695,"props":1781,"children":1782},{},[1783],{"type":48,"tag":63,"props":1784,"children":1786},{"className":1785},[],[1787],{"type":54,"value":1712},{"type":48,"tag":1695,"props":1789,"children":1790},{},[1791],{"type":54,"value":1792},"Icon slug from the set in src\u002Fadmin\u002Fcomponents\u002Fideation\u002Fassistant-icon.js",{"type":48,"tag":1668,"props":1794,"children":1795},{},[1796,1805,1814],{"type":48,"tag":1695,"props":1797,"children":1798},{},[1799],{"type":48,"tag":63,"props":1800,"children":1802},{"className":1801},[],[1803],{"type":54,"value":1804},"is_configured()",{"type":48,"tag":1695,"props":1806,"children":1807},{},[1808],{"type":48,"tag":63,"props":1809,"children":1811},{"className":1810},[],[1812],{"type":54,"value":1813},"bool",{"type":48,"tag":1695,"props":1815,"children":1816},{},[1817],{"type":54,"value":1818},"Whether the channel is ready to send",{"type":48,"tag":1668,"props":1820,"children":1821},{},[1822,1831,1839],{"type":48,"tag":1695,"props":1823,"children":1824},{},[1825],{"type":48,"tag":63,"props":1826,"children":1828},{"className":1827},[],[1829],{"type":54,"value":1830},"send( Notification $notification )",{"type":48,"tag":1695,"props":1832,"children":1833},{},[1834],{"type":48,"tag":63,"props":1835,"children":1837},{"className":1836},[],[1838],{"type":54,"value":1813},{"type":48,"tag":1695,"props":1840,"children":1841},{},[1842],{"type":54,"value":1843},"Deliver a notification",{"type":48,"tag":1668,"props":1845,"children":1846},{},[1847,1856,1865],{"type":48,"tag":1695,"props":1848,"children":1849},{},[1850],{"type":48,"tag":63,"props":1851,"children":1853},{"className":1852},[],[1854],{"type":54,"value":1855},"test_connection()",{"type":48,"tag":1695,"props":1857,"children":1858},{},[1859],{"type":48,"tag":63,"props":1860,"children":1862},{"className":1861},[],[1863],{"type":54,"value":1864},"true|WP_Error",{"type":48,"tag":1695,"props":1866,"children":1867},{},[1868],{"type":54,"value":1869},"Verify the connection works",{"type":48,"tag":1668,"props":1871,"children":1872},{},[1873,1882,1891],{"type":48,"tag":1695,"props":1874,"children":1875},{},[1876],{"type":48,"tag":63,"props":1877,"children":1879},{"className":1878},[],[1880],{"type":54,"value":1881},"sanitize_settings( array $input )",{"type":48,"tag":1695,"props":1883,"children":1884},{},[1885],{"type":48,"tag":63,"props":1886,"children":1888},{"className":1887},[],[1889],{"type":54,"value":1890},"array",{"type":48,"tag":1695,"props":1892,"children":1893},{},[1894],{"type":54,"value":1895},"Sanitize form input",{"type":48,"tag":57,"props":1897,"children":1898},{},[1899,1901,1907,1909,1915],{"type":54,"value":1900},"Settings are declared, not drawn. Override ",{"type":48,"tag":63,"props":1902,"children":1904},{"className":1903},[],[1905],{"type":54,"value":1906},"get_settings_schema()",{"type":54,"value":1908}," to return an array of field definitions; the base class puts it on the channel's REST payload via ",{"type":48,"tag":63,"props":1910,"children":1912},{"className":1911},[],[1913],{"type":54,"value":1914},"to_array()",{"type":54,"value":1916},", and the React admin renders the form from it. There is no PHP-rendered settings form — a channel never emits settings markup of its own.",{"type":48,"tag":72,"props":1918,"children":1920},{"id":1919},"built-in-base-class-helpers",[1921],{"type":54,"value":1922},"Built-in Base Class Helpers",{"type":48,"tag":57,"props":1924,"children":1925},{},[1926,1928,1933],{"type":54,"value":1927},"These are provided by ",{"type":48,"tag":63,"props":1929,"children":1931},{"className":1930},[],[1932],{"type":54,"value":68},{"type":54,"value":1934}," and should not be overridden:",{"type":48,"tag":1936,"props":1937,"children":1938},"ul",{},[1939,1956],{"type":48,"tag":88,"props":1940,"children":1941},{},[1942,1948,1950],{"type":48,"tag":63,"props":1943,"children":1945},{"className":1944},[],[1946],{"type":54,"value":1947},"$this->get_settings()",{"type":54,"value":1949}," -- reads stored settings from ",{"type":48,"tag":63,"props":1951,"children":1953},{"className":1952},[],[1954],{"type":54,"value":1955},"wp_options",{"type":48,"tag":88,"props":1957,"children":1958},{},[1959,1965],{"type":48,"tag":63,"props":1960,"children":1962},{"className":1961},[],[1963],{"type":54,"value":1964},"$this->update_settings( $settings )",{"type":54,"value":1966}," -- writes settings",{"type":48,"tag":72,"props":1968,"children":1970},{"id":1969},"registration",[1971],{"type":54,"value":1972},"Registration",{"type":48,"tag":57,"props":1974,"children":1975},{},[1976,1978,1984,1986,1992,1994,2000],{"type":54,"value":1977},"Channels register via the ",{"type":48,"tag":63,"props":1979,"children":1981},{"className":1980},[],[1982],{"type":54,"value":1983},"vip_workflows_register_notification_channels",{"type":54,"value":1985}," action, which receives a ",{"type":48,"tag":63,"props":1987,"children":1989},{"className":1988},[],[1990],{"type":54,"value":1991},"$dispatcher",{"type":54,"value":1993}," object. Call ",{"type":48,"tag":63,"props":1995,"children":1997},{"className":1996},[],[1998],{"type":54,"value":1999},"$dispatcher->register_channel( new YourChannel() )",{"type":54,"value":2001},".",{"type":48,"tag":72,"props":2003,"children":2005},{"id":2004},"testing",[2006],{"type":54,"value":2007},"Testing",{"type":48,"tag":84,"props":2009,"children":2010},{},[2011,2021,2026,2031,2036],{"type":48,"tag":88,"props":2012,"children":2013},{},[2014,2016],{"type":54,"value":2015},"Place the plugin directory alongside ",{"type":48,"tag":63,"props":2017,"children":2019},{"className":2018},[],[2020],{"type":54,"value":163},{"type":48,"tag":88,"props":2022,"children":2023},{},[2024],{"type":54,"value":2025},"Activate it in WordPress admin",{"type":48,"tag":88,"props":2027,"children":2028},{},[2029],{"type":54,"value":2030},"Go to Integrations > Notification Channels to see the channel",{"type":48,"tag":88,"props":2032,"children":2033},{},[2034],{"type":54,"value":2035},"Configure the webhook URL and use \"Test Connection\" to verify",{"type":48,"tag":88,"props":2037,"children":2038},{},[2039,2041,2047],{"type":54,"value":2040},"Route an event to the channel on the ",{"type":48,"tag":63,"props":2042,"children":2044},{"className":2043},[],[2045],{"type":54,"value":2046},"Routing",{"type":54,"value":2048}," tab, then trigger a workflow transition to test delivery",{"type":48,"tag":2050,"props":2051,"children":2052},"style",{},[2053],{"type":54,"value":2054},"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":2056,"total":1184},[2057,2078,2096,2110,2123,2140,2155,2167,2182,2199,2210,2225],{"slug":2058,"name":2058,"fn":2059,"description":2060,"org":2061,"tags":2062,"stars":2075,"repoUrl":2076,"updatedAt":2077},"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},[2063,2066,2069,2072],{"name":2064,"slug":2065,"type":15},"Frontend","frontend",{"name":2067,"slug":2068,"type":15},"Productivity","productivity",{"name":2070,"slug":2071,"type":15},"UX Copy","ux-copy",{"name":2073,"slug":2074,"type":15},"UX Design","ux-design",484,"https:\u002F\u002Fgithub.com\u002FAutomattic\u002Fstudio","2026-05-06T05:40:01.516544",{"slug":2079,"name":2079,"fn":2080,"description":2081,"org":2082,"tags":2083,"stars":2075,"repoUrl":2076,"updatedAt":2095},"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},[2084,2087,2090,2093],{"name":2085,"slug":2086,"type":15},"Block Editor","block-editor",{"name":2088,"slug":2089,"type":15},"CSS","css",{"name":2091,"slug":2092,"type":15},"HTML","html",{"name":2094,"slug":36,"type":15},"WordPress","2026-08-29T09:23:44.042569",{"slug":2097,"name":2097,"fn":2098,"description":2099,"org":2100,"tags":2101,"stars":2075,"repoUrl":2076,"updatedAt":2109},"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},[2102,2105,2108],{"name":2103,"slug":2104,"type":15},"Pricing","pricing",{"name":2106,"slug":2107,"type":15},"Reference","reference",{"name":2094,"slug":36,"type":15},"2026-07-02T07:42:33.654791",{"slug":2111,"name":2111,"fn":2112,"description":2113,"org":2114,"tags":2115,"stars":2075,"repoUrl":2076,"updatedAt":2122},"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},[2116,2119],{"name":2117,"slug":2118,"type":15},"Creative","creative",{"name":2120,"slug":2121,"type":15},"Image Generation","image-generation","2026-09-01T08:30:34.994105",{"slug":2124,"name":2124,"fn":2125,"description":2126,"org":2127,"tags":2128,"stars":2075,"repoUrl":2076,"updatedAt":2139},"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},[2129,2132,2135,2138],{"name":2130,"slug":2131,"type":15},"CMS","cms",{"name":2133,"slug":2134,"type":15},"Migration","migration",{"name":2136,"slug":2137,"type":15},"Web Development","web-development",{"name":2094,"slug":36,"type":15},"2026-07-09T06:47:33.454311",{"slug":2141,"name":2141,"fn":2142,"description":2143,"org":2144,"tags":2145,"stars":2075,"repoUrl":2076,"updatedAt":2154},"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},[2146,2149,2150,2153],{"name":2147,"slug":2148,"type":15},"Audit","audit",{"name":2064,"slug":2065,"type":15},{"name":2151,"slug":2152,"type":15},"Performance","performance",{"name":2094,"slug":36,"type":15},"2026-05-06T05:40:06.433267",{"slug":2156,"name":2156,"fn":2157,"description":2158,"org":2159,"tags":2160,"stars":2075,"repoUrl":2076,"updatedAt":2166},"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},[2161,2164,2165],{"name":2162,"slug":2163,"type":15},"Content Creation","content-creation",{"name":17,"slug":18,"type":15},{"name":2094,"slug":36,"type":15},"2026-08-22T03:27:47.937007",{"slug":2168,"name":2168,"fn":2169,"description":2170,"org":2171,"tags":2172,"stars":2075,"repoUrl":2076,"updatedAt":2181},"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},[2173,2174,2177,2180],{"name":2147,"slug":2148,"type":15},{"name":2175,"slug":2176,"type":15},"Marketing","marketing",{"name":2178,"slug":2179,"type":15},"SEO","seo",{"name":2094,"slug":36,"type":15},"2026-05-06T05:40:05.196367",{"slug":2183,"name":2183,"fn":2184,"description":2185,"org":2186,"tags":2187,"stars":2075,"repoUrl":2076,"updatedAt":2198},"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},[2188,2191,2194,2197],{"name":2189,"slug":2190,"type":15},"Design","design",{"name":2192,"slug":2193,"type":15},"Product Management","product-management",{"name":2195,"slug":2196,"type":15},"Specs","specs",{"name":2094,"slug":36,"type":15},"2026-05-06T05:40:02.739409",{"slug":2200,"name":2200,"fn":2201,"description":2202,"org":2203,"tags":2204,"stars":2075,"repoUrl":2076,"updatedAt":2209},"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},[2205,2208],{"name":2206,"slug":2207,"type":15},"CLI","cli",{"name":2094,"slug":36,"type":15},"2026-09-04T07:24:24.148676",{"slug":2211,"name":2211,"fn":2212,"description":2213,"org":2214,"tags":2215,"stars":2075,"repoUrl":2076,"updatedAt":2224},"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},[2216,2219,2222,2223],{"name":2217,"slug":2218,"type":15},"Content Strategy","content-strategy",{"name":2220,"slug":2221,"type":15},"Data Cleaning","data-cleaning",{"name":2178,"slug":2179,"type":15},{"name":2094,"slug":36,"type":15},"2026-05-06T05:40:03.966799",{"slug":2226,"name":2226,"fn":2227,"description":2228,"org":2229,"tags":2230,"stars":2075,"repoUrl":2076,"updatedAt":2240},"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},[2231,2234,2235,2238],{"name":2232,"slug":2233,"type":15},"Animation","animation",{"name":2189,"slug":2190,"type":15},{"name":2236,"slug":2237,"type":15},"Typography","typography",{"name":2239,"slug":2226,"type":15},"Visual Design","2026-07-24T05:40:57.887452",{"items":2242,"total":216},[2243,2255,2263],{"slug":2244,"name":2244,"fn":2245,"description":2246,"org":2247,"tags":2248,"stars":28,"repoUrl":29,"updatedAt":2254},"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},[2249,2252,2253],{"name":2250,"slug":2251,"type":15},"Agents","agents",{"name":17,"slug":18,"type":15},{"name":2094,"slug":36,"type":15},"2026-09-04T08:01:04.234021",{"slug":4,"name":4,"fn":5,"description":6,"org":2256,"tags":2257,"stars":28,"repoUrl":29,"updatedAt":30},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[2258,2259,2260,2261,2262],{"name":13,"slug":14,"type":15},{"name":20,"slug":21,"type":15},{"name":17,"slug":18,"type":15},{"name":23,"slug":24,"type":15},{"name":26,"slug":27,"type":15},{"slug":2264,"name":2264,"fn":2265,"description":2266,"org":2267,"tags":2268,"stars":28,"repoUrl":29,"updatedAt":2274},"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},[2269,2272,2273],{"name":2270,"slug":2271,"type":15},"Code Analysis","code-analysis",{"name":17,"slug":18,"type":15},{"name":2094,"slug":36,"type":15},"2026-09-04T08:00:44.370747"]