Skip to content
Gaurav TiwariDocs

Hooks and Filters Reference

Updated October 30, 2026

You want a new ticket to post into your own tool, a custom field to reach Chat or your analytics script to survive on the docs pages. Editing the plugin works until the next update wipes it out.

Core Support exposes actions and filters for this, all named core_support_. This page lists them by feature, with the arguments the code passes and what each one changes. Put your code in a small plugin or a code snippets plugin, never in Core Support’s own files.

How to Read This Page

  • Action hooks run your code at a moment. Use add_action().
  • Filter hooks pass a value through your code and use what you return. Use add_filter(), and always return a value of the same type.
  • Arguments are listed in order. When a hook passes more than 1 argument, set the accepted-args count in add_action() or add_filter().
  • Defaults are the values Core Support passes before any filter runs.

Tickets

  • core_support_ticket_created (action): int $ticket_id. Fires after a ticket is opened by anyone other than an agent: a customer in the portal, an email, a form, a connected site or a Chat handoff. Team alerts and the FluentCRM sync run on this hook. Tickets brought in by an import don’t fire it.
  • core_support_ticket_deleted (action): int $ticket_id, int $actor_id. Fires after a ticket and everything in it is deleted for good. $actor_id is the user who deleted it. Undoing an import fires it for each ticket the import added, with 0 as the actor.
  • core_support_customer_replied (action): int $ticket_id, int $message_id. Fires after a customer’s reply is added to a ticket. Agent replies and notes don’t fire it.
  • core_support_roadmap_requested (action): int $item_id. Fires after a visitor suggests a feature on a roadmap page. Team alerts and team emails for suggestions run on this hook.
  • core_support_guest_ticket_is_spam (filter): bool $verdict, array $fields. Whether a message from the ticket form for visitors without an account is spam. $verdict is Akismet’s answer, or false without Akismet. $fields holds name, email, subject and message. Spam waits in Incoming mail and opens no ticket.
add_action('core_support_ticket_created', function (int $ticket_id): void {
    error_log('New support ticket #' . $ticket_id);
});

// Treat any guest ticket that links to a URL shortener as spam.
add_filter('core_support_guest_ticket_is_spam', function (bool $spam, array $fields): bool {
    return $spam || str_contains($fields['message'], 'bit.ly/');
}, 10, 2);

Forms and Team Alerts

  • core_support_form_ticket_fields (filter): array $fields, string $plugin, string $form_id. The submitted fields before Core Support picks the email, name, subject and message. Each field is an array with key, label, value and type. $plugin is cf7, wpforms, gravityforms or fluentforms. Core Forms uses its own action and doesn’t pass through this filter.
  • core_support_alert_channels (filter): array $channels. The team alert channels, as objects implementing Gatilab\CoreSupport\Notifications\Channel. The built-in 5 are Telegram, Pushover, Discord, Slack and Webhook. A channel key must be 2 to 31 lowercase letters and digits starting with a letter, and every setting the channel owns starts with that key. Invalid or duplicate keys are skipped.

Open Tickets from Contact Forms and Team Alerts on Telegram, Pushover, Discord, Slack or a Webhook cover the screens these hooks sit behind.

Support, Docs and Changelog Pages

  • core_support_header_links (filter): array $links, string $page. The header links and buttons from Settings → Header and footer. Each link has label, url and style (link, button or primary). $page is docs, changelogs or portal. Links without a label or address are dropped.
  • core_support_footer_links (filter): array $links, string $page. The same for the footer links.
  • core_support_standalone_handles (filter): array $handles, as handle => true. On portal and changelog pages, which load only Core Support’s styles and scripts, this is the full list of handles kept. Add yours, such as an analytics script. On docs pages it starts empty, and a handle you add stays even when it looks like the theme’s.
  • core_support_theme_handle_prefixes (filter): array $prefixes, array $themes. Handle prefixes treated as the active theme’s on docs pages. $themes holds the active theme’s folder name and its parent’s. A prefix ending in - or _ matches the start of a handle.
add_filter('core_support_standalone_handles', function (array $handles): array {
    $handles['my-analytics'] = true;
    return $handles;
});

Every Core Support page also carries a core-support class on its body: the wp-admin screens, docs, changelog, roadmap and support portal pages, and your own pages that hold the portal blocks. Your theme’s CSS or Custom code can target body.core-support without a filter.

Docs Pages, Your Theme and Other Plugins explains which styles and scripts each page type keeps.

Changelogs

  • core_support_changelog_category (filter): string $category, string $label. The badge a change label maps to, such as fixed, or other when nothing matches. $label is the label as written. Custom badges from Settings → Changelogs use this filter and come back as custom-{slug}.
  • core_support_changelog_tone (filter): string $tone, string $category. A badge’s color: green, blue, orange, red, yellow or muted, or your own color as a hex code, rgb(), hsl(), oklch() or var(--name).
  • core_support_changelog_intro (filter): string $intro. The line under the heading on /changelogs/, also used as that page’s description. Default: “Every release across our products, newest first.”

Admin Screens

  • core_support_docs_url (filter): string $url, string $topic. The guide a question mark beside an admin section opens, such as https://gauravtiwari.org/docs/core-support/email/imap/. $topic names the section, such as imap, team-alerts or changelogs. Return another https:// address to send the links to your own docs, or an empty string to hide them.
// White-label: point every guide link at your own docs.
add_filter('core_support_docs_url', function (string $url, string $topic): string {
    return 'https://docs.example.com/help-desk/' . $topic . '/';
}, 10, 2);

// Or hide the question marks.
add_filter('core_support_docs_url', '__return_empty_string');

Chat: Placement and Page Context

  • core_support_chat_show_launcher (filter): bool $shown. Whether the chat button loads on the current page, after the Where the button shows settings are applied. Return false to keep it off a page or true to add it. Docs shown inside a connected site’s frame turn it off through this filter.
  • core_support_chat_page_context (filter): array $context, string $origin_url. The page the visitor is on, as sent to the model: url, title, content and post_id.

Chat: Settings

  • core_support_chat_default_settings (filter): array $defaults. Every Chat setting with its default. Saved values and the CORE_SUPPORT_CHAT constant override these.
  • core_support_chat_settings_sanitize (filter): array $output, array $input. The cleaned Chat settings just before they are saved, with the raw form input.

Chat: Providers and Models

  • core_support_chat_pre_llm_provider (filter): null $override, string $provider, string $task. Return an LLMProvider object to replace the chat model completely. $task is answers, followups or titles.
  • core_support_chat_llm_provider (filter): LLMProvider $llm, string $task. The built-in chat provider for a task. The built-in provider is created first, so its API key must already be set.
  • core_support_chat_pre_embedding_provider (filter): null $override, string $provider. Return an EmbeddingProvider object to replace the search model completely.
  • core_support_chat_embedding_provider (filter): EmbeddingProvider $embeddings. The built-in search model.
  • core_support_chat_embedding_dimensions (filter): int $dimensions, string $provider, string $model. The vector size stored for a search model. Default 512; 0 uses the model’s full size. $provider is openai or voyage. Changing it learns every post again in the background.
  • core_support_chat_moderation_provider (filter): ModerationProvider $moderation. The message check that runs before an answer. It uses OpenAI moderation when an OpenAI key is saved, and no check otherwise.
  • core_support_chat_vector_store (filter): VectorStore $store. Where learned passages are stored and searched. Default: the site’s database.
  • core_support_chat_model_catalog (filter): array $catalog. The providers, models, search models and thinking levels shown on Core Support → AI and Chat.
  • core_support_chat_is_reasoning_model (filter): bool $is_reasoning, string $model. Runs only for a model the built-in list doesn’t recognize, with false. Return true for a model that takes max_completion_tokens and refuses custom sampling values.
  • core_support_chat_http_timeout (filter): int $seconds. The timeout for provider requests. Default 60, minimum 1.

Chat: What It Learns

  • core_support_chat_post_html (filter): string $html, WP_Post $post. A post’s HTML after the_content, before it’s split into passages. Changelogs use it to add their kept release history.
  • core_support_chat_chunk_context (filter): string $context, WP_Post $post. The line every passage of a post starts with. Default: the title, after the docs product when there is one.
  • core_support_chat_post_fields (filter): array $fields, WP_Post $post. The custom fields Chat learns from a post. Each has name, label and value. Values you add are cleaned the same way, and empty ones are dropped.
  • core_support_chat_product_facts (filter): array $lines, WP_Post $post. The “Product facts” lines learned with a product, as Label: value strings. Add lines for your own product data or post types. Each line is cut at 400 characters and duplicates are dropped.
  • core_support_chat_watched_meta (filter): array $keys. Post meta keys whose changes mark a post for learning again. Changelogs add their release dates, pre-releases and kept history.
  • core_support_chat_max_queued_posts (filter): int $max, string $post_type. The most posts one reindex request queues. Default 5000.
  • core_support_chat_sweep_batch (filter): int $batch. The most posts one 30-minute check learns. Default 25, minimum 1.
  • core_support_chat_sweep_checks (filter): int $checks. How many unchanged learned posts each check also compares, oldest first, for changes no hook reported. Default 10; 0 turns it off.
  • core_support_chat_sweep_seconds (filter): int $seconds. How long one check may spend learning. Default 20, minimum 5.
add_filter('core_support_chat_product_facts', function (array $lines, WP_Post $post): array {
    $warranty = get_post_meta($post->ID, 'warranty_months', true);
    if ($warranty !== '') {
        $lines[] = 'Warranty: ' . $warranty . ' months';
    }
    return $lines;
}, 10, 2);

Chat: Search and the Prompt

  • core_support_chat_retrieved_chunks (filter): array $chunks, string $message. The passages chosen for an answer, before they are sent to the model. Each has id, score and metadata.
  • core_support_chat_full_scan_max_chunks (filter): int $max, string $embedding_model, int $dimensions. The most passages compared with every question. Default 5,000 at 512 dimensions, proportionally fewer for longer vectors. Above it, search scores a shortlist from word search.
  • core_support_chat_retrieval_candidates (filter): array $rows, string $text_query, string $embedding_model. The shortlist rows before they are scored. It runs only when search works from a shortlist instead of every passage.
  • core_support_chat_fallback_candidates (filter): int $limit. How many passages are scanned when word search finds nothing, above the full-scan limit. Default 400.
  • core_support_chat_rrf_k (filter): int $k. The constant used to combine meaning and word rankings. Default 60, minimum 1. Lower values give the top of each ranking more weight.
  • core_support_chat_max_prompt_faqs (filter): int $max, string $message. How many curated Q&A entries go into the prompt. Default 12; 0 sends every enabled entry.

These filters run while the visitor waits for an answer, so a higher limit costs response time.

Chat: Visitors and Limits

  • core_support_chat_trust_cloudflare (filter): bool $trust. Whether Cloudflare’s published edge ranges count as trusted proxies when Chat reads the visitor’s address. Default true.
  • core_support_chat_trusted_proxies (filter): array $proxies. Proxy addresses and CIDR ranges whose forwarding headers are trusted, after CORE_SUPPORT_TRUSTED_PROXIES and the Cloudflare ranges are added.
  • core_support_chat_rate_limit (filter): array $limits, string $bucket. The limit for one Chat bucket as [limit, window in seconds]. A limit or window of 0 turns that bucket off. The buckets and their defaults: – chat_session: 20 messages a minute per conversation, [20, 60] – chat_ip: 60 messages in 10 minutes per IP address, [60, 600] – chat_global: 240 messages a minute for the whole site, [240, 60] – contact_ip: 5 tickets an hour per IP address from “Talk to a person”, [5, 3600]
add_filter('core_support_chat_rate_limit', function (array $limits, string $bucket): array {
    return $bucket === 'chat_ip' ? [120, 600] : $limits;
}, 10, 2);

Chat: Actions

  • core_support_chat_message_answered (action): int $thread_id, string $message, string $reply, array $sources. After Chat answers a question.
  • core_support_chat_unanswered_question (action): int $thread_id, string $message. After an answer for which search found no passages. Useful for finding gaps in your docs.
  • core_support_chat_message_flagged (action): string $message, array $moderation. When moderation flags a message. $moderation has flagged, categories and scores. The visitor gets the fallback message.
  • core_support_chat_handoff (action): int $thread_id, int $ticket_id. After a conversation becomes a ticket through “Talk to a person”.
  • core_support_chat_thread_titled (action): int $thread_id, string $title. After the model names a conversation. It never fires while Conversation titles is set to No model: first words of the question.
  • core_support_chat_post_indexed (action): int $post_id, int $chunk_count. After a post is learned.
  • core_support_chat_post_index_skipped (action): int $post_id. When a post’s passages haven’t changed, so no embedding request is made.
  • core_support_chat_post_index_busy (action): int $post_id. When another run is already learning the post. Core Support marks it to learn again.
  • core_support_chat_post_forgotten (action): int $post_id. After a post’s passages are removed.
  • core_support_chat_search_model_switched (action): string $from, string $to. When search switches to a newly learned model. The old model’s passages are deleted next.
  • core_support_chat_sweep_done (action): array $result. After a 30-minute check, with time, learned, unchanged, forgotten, waiting and failed.
add_action('core_support_chat_unanswered_question', function (int $thread_id, string $message): void {
    error_log('Chat had no docs for: ' . $message);
}, 10, 2);

Customers and Background Jobs

  • core_support_customer_created (action): int $customer_id, string $source. Fires when a new customer record is created. $source says where the person came from: tickets, fluentcart, woocommerce or edd, or an import such as zendesk:acme or file: followed by the file’s fingerprint. FluentCRM never creates customers, so it never fires this.
  • core_support_customers_merged (action): int $from, int $into. Fires after one customer is merged into another. $from is the closed record, which now points at $into.
  • core_support_job_stepped (action): Gatilab\CoreSupport\Jobs\Job $job. Fires after each step of a background job: a customer sync, an update of every customer, an import or an undo. The job has public id, type, source, status, counts and lastError properties, among others. status is queued, running, waiting, done, failed, cancelled or undone.
add_action('core_support_customer_created', function (int $customer_id, string $source): void {
    error_log('New customer #' . $customer_id . ' from ' . $source);
}, 10, 2);

// Log every background job that stops with an error.
add_action('core_support_job_stepped', function ($job): void {
    if ($job->status === 'failed') {
        error_log('Core Support job #' . $job->id . ' stopped: ' . $job->lastError);
    }
});

Keep One Record for Each Customer explains when records are created and merged.

Good to Know

  • Agent actions such as a reply, a private note, a status change or an assignment have no hooks in 1.3.0.
  • Scheduled event hooks such as core_support_deliver are WP-Cron events, not extension points. Diagnostics and WP-CLI Commands lists them.
  • Return the type a filter expects. The header and footer link filters, for example, fall back to the original links when you don’t return an array.
Share

Was this helpful?

Still stuck? Open a support ticket