{"id":43,"date":"2026-09-09T04:25:58","date_gmt":"2026-09-09T04:25:58","guid":{"rendered":"https:\/\/nirohelp.com\/docs\/43\/action-hooks\/"},"modified":"2026-09-09T04:25:58","modified_gmt":"2026-09-09T04:25:58","slug":"action-hooks","status":"publish","type":"nirohelp_doc","link":"https:\/\/nirohelp.com\/docs\/developers\/action-hooks\/","title":{"rendered":"Action hooks reference"},"content":{"rendered":"<p>NiroHelp fires actions at every meaningful moment in a doc&#8217;s or a ticket&#8217;s<br \/>\nlife. Hook them to post to Slack, log to your own table, sync to a CRM, or<br \/>\nanything else.<\/p>\n<p>Note the naming is inconsistent by history: most ticket hooks use hyphens<br \/>\n(<code>nirohelp-tickets-\u2026<\/code>), two use underscores (<code>nirohelp_tickets_comment_added<\/code>,<br \/>\n<code>nirohelp_user_inserted<\/code>). Copy the names exactly as written.<\/p>\n<h2>Tickets<\/h2>\n<table>\n<thead>\n<tr>\n<th>Hook<\/th>\n<th>Args<\/th>\n<th>Fired when<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>nirohelp-tickets-ticket_created<\/code><\/td>\n<td><code>$ticket<\/code><\/td>\n<td>A ticket is created \u2014 front-end form, embed widget or <code>POST \/tickets\/<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>nirohelp-tickets-client_commented<\/code><\/td>\n<td><code>$ticket<\/code><\/td>\n<td>A client posts a comment.<\/td>\n<\/tr>\n<tr>\n<td><code>nirohelp-tickets-agent_commented<\/code><\/td>\n<td><code>$ticket<\/code><\/td>\n<td>An agent posts a comment.<\/td>\n<\/tr>\n<tr>\n<td><code>nirohelp-tickets-ticket_status_changed<\/code><\/td>\n<td><code>$new, $old, $ticket<\/code><\/td>\n<td>The status changed, and <strong>both<\/strong> statuses are registered NiroHelp statuses.<\/td>\n<\/tr>\n<tr>\n<td><code>nirohelp-tickets-ticket_status_{new}_to_{old}<\/code><\/td>\n<td><code>$ticket<\/code><\/td>\n<td>Same event, dynamic name. Note the order \u2014 new first, old second.<\/td>\n<\/tr>\n<tr>\n<td><code>nirohelp-tickets-agent_changed<\/code><\/td>\n<td><code>$new_agent_id, $old_agent_id<\/code><\/td>\n<td>The assigned agent changed.<\/td>\n<\/tr>\n<tr>\n<td><code>nirohelp_tickets_comment_added<\/code><\/td>\n<td><code>$comment_id, $ticket_id<\/code><\/td>\n<td>Low-level; fires inside the model before the role-specific hooks.<\/td>\n<\/tr>\n<tr>\n<td><code>nirohelp-tickets-ticket_model_status_changed<\/code><\/td>\n<td>(none)<\/td>\n<td>Internal; fires in the Ticket model right after a status is set.<\/td>\n<\/tr>\n<tr>\n<td><code>nirohelp-tickets-login<\/code><\/td>\n<td>(none)<\/td>\n<td>Fired by the four ticket views when the visitor is logged out. <code>Front::show_login_form()<\/code> listens on it. Hook it to render your own login UI.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Because <code>nirohelp-tickets-ticket_status_changed<\/code> requires both statuses to be<br \/>\nregistered, moving a ticket to <strong>Trash<\/strong> does not fire it \u2014 <code>trash<\/code> is not one<br \/>\nof NiroHelp&#8217;s statuses. That is deliberate: it stops a deletion sending<br \/>\n&#8220;resolved&#8221; emails and adding a bot note.<\/p>\n<h2>Auth and users<\/h2>\n<table>\n<thead>\n<tr>\n<th>Hook<\/th>\n<th>Args<\/th>\n<th>Fired when<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>nirohelp-tickets-code_generated<\/code><\/td>\n<td><code>$email, $code<\/code><\/td>\n<td>A 6-digit login code was generated. <code>Controllers\\Common\\Email<\/code> listens and sends it.<\/td>\n<\/tr>\n<tr>\n<td><code>nirohelp-tickets-magic_link_sent<\/code><\/td>\n<td><code>$email, $link<\/code><\/td>\n<td>A one-click login link was minted, in <code>magic_link<\/code> mode. Same listener.<\/td>\n<\/tr>\n<tr>\n<td><code>nirohelp-tickets-user_found<\/code><\/td>\n<td><code>$data<\/code><\/td>\n<td>An existing user was matched during login.<\/td>\n<\/tr>\n<tr>\n<td><code>nirohelp-logged_in<\/code><\/td>\n<td><code>$user_id<\/code><\/td>\n<td>A client was signed in through the <code>?nirohelplogin={key}<\/code> flow.<\/td>\n<\/tr>\n<tr>\n<td><code>nirohelp_user_inserted<\/code><\/td>\n<td><code>$user_id<\/code><\/td>\n<td>A new NiroHelp client account was created.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Docs<\/h2>\n<table>\n<thead>\n<tr>\n<th>Hook<\/th>\n<th>Args<\/th>\n<th>Fired when<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>nirohelp-doc_created<\/code><\/td>\n<td><code>$doc<\/code><\/td>\n<td>A doc is created through <code>POST \/docs\/<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>nirohelp-before_doc_content<\/code><\/td>\n<td><code>$doc<\/code><\/td>\n<td>Inside the single-doc template, before the post body.<\/td>\n<\/tr>\n<tr>\n<td><code>nirohelp-after_doc_content<\/code><\/td>\n<td><code>$doc<\/code><\/td>\n<td>Inside the single-doc template, after the post body. The plugin&#8217;s own pagination and rating buttons hang off this.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>AI<\/h2>\n<table>\n<thead>\n<tr>\n<th>Hook<\/th>\n<th>Args<\/th>\n<th>Fired when<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>nirohelp_ai_auto_respond<\/code><\/td>\n<td><code>$ticket_id<\/code><\/td>\n<td>The auto-responder WP-Cron event. One argument. Unhook the plugin&#8217;s callback and add your own to keep the scheduling and cancellation while writing the reply yourself.<\/td>\n<\/tr>\n<tr>\n<td><code>nirohelp_daily_briefing<\/code><\/td>\n<td>(none)<\/td>\n<td>The daily briefing cron event, scheduled for 06:00 site time.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>A practical example<\/h2>\n<p>Post to Slack whenever a <em>Severe<\/em> ticket lands:<\/p>\n<pre><code class=\"language-php\">add_action( 'nirohelp-tickets-ticket_created', function ( $ticket ) {\n    if ( 'severe' !== $ticket-&gt;get_meta( 'urgency' ) ) {\n        return;\n    }\n\n    wp_remote_post( 'https:\/\/hooks.slack.com\/...', [\n        'headers' =&gt; [ 'Content-Type' =&gt; 'application\/json' ],\n        'body'    =&gt; wp_json_encode( [\n            'text' =&gt; sprintf( 'New severe ticket: %s', $ticket-&gt;get_title() ),\n        ] ),\n    ] );\n} );\n<\/code><\/pre>\n<p>And to react only to a specific transition:<\/p>\n<pre><code class=\"language-php\">\/\/ A ticket that was Resolved and is now Reopened.\nadd_action( 'nirohelp-tickets-ticket_status_reopened_to_resolved', function ( $ticket ) {\n    \/\/ ...\n} );\n<\/code><\/pre>\n","protected":false},"author":1,"featured_media":0,"template":"","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}}},"nirohelp_product":[],"nirohelp_topic":[12],"class_list":["post-43","nirohelp_doc","type-nirohelp_doc","status-publish","hentry","nirohelp_topic-developers"],"_links":{"self":[{"href":"https:\/\/nirohelp.com\/docs\/wp-json\/wp\/v2\/nirohelp_doc\/43","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nirohelp.com\/docs\/wp-json\/wp\/v2\/nirohelp_doc"}],"about":[{"href":"https:\/\/nirohelp.com\/docs\/wp-json\/wp\/v2\/types\/nirohelp_doc"}],"author":[{"embeddable":true,"href":"https:\/\/nirohelp.com\/docs\/wp-json\/wp\/v2\/users\/1"}],"wp:attachment":[{"href":"https:\/\/nirohelp.com\/docs\/wp-json\/wp\/v2\/media?parent=43"}],"wp:term":[{"taxonomy":"nirohelp_product","embeddable":true,"href":"https:\/\/nirohelp.com\/docs\/wp-json\/wp\/v2\/nirohelp_product?post=43"},{"taxonomy":"nirohelp_topic","embeddable":true,"href":"https:\/\/nirohelp.com\/docs\/wp-json\/wp\/v2\/nirohelp_topic?post=43"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}