Pro hooks reference
Use these hooks to react to what Pro does and to change how it behaves. Pro fires its own wcbp_* actions and filters, plus a few hooks in the Free wcb_* namespace where Pro shares the contract with Free. It also answers a set of Free filters. For Free’s hooks see the Free developer guide.
Actions Pro fires
Section titled “Actions Pro fires”| Hook | Args | Use to |
|---|---|---|
wcbp_application_stage_changed |
$app_id, $old_stage, $new_stage |
A person moved a card to another stage on the Kanban board, through PUT /applications/{id}/stage. Args are the application ID and the old and new stage IDs (integers). Pro’s own status sync listens here. |
wcbp_board_deleted |
$board_id |
A board was deleted through DELETE /boards/{id}. Pro has already removed the board’s stages and unlinked its jobs when this fires. |
wcbp_credit_consumed |
$user_id, $amount, $item_id |
The SDK recorded a credit deduction for this plugin (re-emitted from the SDK’s wbcom_credits_deducted, scoped to this plugin). $item_id is usually the job. Use for logging or per-purchase notifications. |
wcbp_credits_low |
$user_id, $balance |
The SDK reported a credit balance at or below the configured low threshold (re-emitted from the SDK’s wbcom_credits_low, scoped to this plugin). |
wcbp_credits_topped_up |
$user_id, $amount, $note |
The SDK recorded a credit top-up (re-emitted from the SDK’s wbcom_credits_topped_up, scoped to this plugin). |
wcbp_field_group_saved |
$group_id |
A field-builder group was created or updated. |
wcbp_field_group_deleted |
$group_id |
A field-builder group was deleted. |
wcbp_field_definition_saved |
$field_id, $group_id |
A field-builder field definition was created or updated ($group_id is 0 on update-by-id). |
wcbp_field_definition_deleted |
$field_id |
A field-builder field definition was deleted. |
wcbp_field_value_saved |
$post_id, $key, $value |
A custom field value on a job/company/candidate/resume was saved via the field builder. |
wcbp_resume_published |
$resume_id, $post |
A candidate’s resume went public. $post is the WP_Post. Use for search indexing or notifications. |
wcbp_send_alert_email |
$alert, $jobs |
Pro is sending a job-alert email through its built-in email channel. $alert is the alert row, $jobs the matched job IDs. To add another channel such as SMS or Slack, use the wcbp_alert_dispatch_channels filter instead. |
wcbp_open_to_work_before_item |
$resume, $user, $user_id |
Render extra markup before each Open-to-Work listing item. |
wcbp_open_to_work_after_item |
$resume, $user, $user_id |
Render extra markup after each Open-to-Work listing item. |
wcbp_my_applications_table_header |
$is_employer_view |
Render extra <th> cells at the end of the My Applications table header. $is_employer_view is true on the employer-facing view, false on the candidate view. |
wcbp_my_applications_table_row |
$application, $job_id, $is_employer_view |
Render extra <td> cells at the end of each My Applications row. $application is the application WP_Post. Pair with wcbp_my_applications_table_header so column counts line up. |
wcbp_credit_hold_reconciled |
$employer_id, $post_id, $amount, $orphan |
The daily wcbp_reconcile_credit_holds cron auto-refunded a credit hold that had no matching deduction or refund after 24 hours (crashed request, dropped REST call). $amount is the original hold amount (positive int); $orphan is the raw ledger row. Hook here to notify an admin or employer. |
wcbp_ai_score_application |
$app_id |
Single-event cron action that scores one application in the background. Pro schedules it for each new application when “Auto-score applicants on submit” is on, and again after a failed scoring attempt. You can fire it yourself with an application ID. See 05-ai-providers.md. |
wcbp_application_stage_assigned |
$app_id, $stage_id, $board_id |
The system placed an application in a pipeline stage (on apply, or when a status change moves the card). Not fired for a person dragging a card. Use it to greet a new applicant. |
wcbp_default_stages_seeded |
$board_id, $first_id |
A board was given the default pipeline stages. $first_id is the first stage. |
wcbp_guest_alert_created |
$alert_id, $email |
A visitor without an account saved a job alert. Pro’s confirmation email (double opt-in) runs from this. |
wcbp_post_geocoded |
$post_id, $lat, $lng, $location |
A job or resume got its coordinates from the background geocoder. |
Pro also fires Free hooks in places where the action semantically belongs to Pro but the contract is shared:
| Hook | Where Pro fires it | Why |
|---|---|---|
wcb_application_status_changed |
modules/pipeline/class-pipeline-module.php |
Pro does not fire this itself. When a card lands in a stage whose outcome is Hired or Rejected, Pro asks Free’s application lifecycle to set that status, and Free fires this action with ($app_id, $old_status, $new_status, $reason, $by). Moving a card out of an outcome stage sets the status back to reviewing. |
wcb_resume_form_simple_extra_fields |
blocks/resume-form-simple/render.php |
Extension point for adding fields to the quick resume form. Passes $attributes. |
wcb_add_more_info_hero_actions |
blocks/resume-single/render.php |
Extension point for adding buttons to the resume hero. Args: $post (the resume WP_Post), $user_id (the owner), $resume (the resume data array). |
wcb_job_csv_imported |
modules/migration/class-csv-importer.php |
Fired once per imported job row with ($post_id, $data). |
wcb_job_imported |
modules/migration/class-csv-importer.php |
Fired once per imported job with ($post_id). |
wcb_notification_created |
modules/notificationsbell/class-notifications-bell-module.php |
Fired after a bell notification row is inserted, with one array arg { user_id, event_type, message, link, id } (id = inserted row id), so a centralised notification center (BuddyNext) can mirror it. It passes the community notification contract as a second argument (null for an admin-only row); see “Community notification contract” below. Shared wcb_ name so one listener covers Free + Pro; Free fires the same hook from its email send. Pro’s PushModule also consumes this event to send native push notifications through Expo - see “Push notifications” below. |
wcb_job_board_id |
modules/pipeline/class-stage-repository.php (StageRepository::board_for_job()) |
Free-owned filter (fired by Free’s Jobs REST endpoint; Pro’s BoardsProModule::resolve_board_id() supplies the multi-board answer). Pro’s pipeline applies it to resolve a job’s owning board, so a stage move can’t be written to a stage from another employer’s board. ($board_id, $job_id). |
wcb_board_credit_cost |
modules/credits/class-job-charge.php |
Free-owned filter (Free’s job forms and Jobs REST endpoint apply it when a job is posted). Pro answers it with the per-board credit_cost setting, and JobCharge applies it again to work out the price of a renewal. ($cost, $board_id). |
wcb_job_republish_credit_cost |
modules/credits/class-job-charge.php |
Free-owned filter. Free applies it when a closed or expired job is republished, and Pro’s JobCharge applies it to the credits it holds for the renewal, starting from the board’s normal cost. One callback can discount both. ($cost, $post, $previous_status). |
wcb_shortcode_attr_aliases |
core/class-pro-plugin.php |
Free-owned camelCase-attribute remap (shortcode attributes lowercase, block.json schemas don’t). Pro’s shortcode-to-block bridge applies it so Pro’s shortcodes (for example [wcbp_featured_candidates]) share the same attribute vocabulary as Free’s. ($aliases). |
Filters Pro fires
Section titled “Filters Pro fires”| Hook | Returns |
|---|---|
wcbp_ai_provider_drivers |
array - map of provider slug to a factory callable returning an AiDriverInterface. Built-in slugs are claude, openai and ollama. Args: $drivers, $credential, $base_url (the last two hold the same value). |
wcbp_ai_provider_requires_api_key |
bool - does the provider need a key (default true)? Args: $requires, $provider. |
wcbp_candidate_resume_data |
array - the grouped resume data sent to AI for scoring and matching. Arg: $user_id. |
wcbp_ai_candidate_matches |
array - the AI candidate-match results before they are returned (args: $matches, $user_id) |
wcbp_ai_ranked_applications |
array - the AI applicant-ranking results before they are returned (args: $ranked, $job_id) |
wcbp_ai_claude_model |
string - the Claude model id used for analysis and ranking. Defaults to the wcbp_ai_anthropic_model option. |
wcbp_ai_score_batch_size |
int - applications scored per background pass (default 25, clamped to 1-100). |
wcbp_ai_rank_max_applications |
int - most applications one rank request scores (default 500). Args: $max, $job_id. |
wcbp_ai_match_scan_cap |
int - number of newest published jobs scored per candidate-match search (default 2000). Bounds the nearest-neighbor scan so a large catalog does not compare every stored vector on each request. |
wcbp_ai_anthropic_model is an option (set on the AI settings screen), not a filter. It stores the chosen Claude model id and is read with get_option() as the default value the wcbp_ai_claude_model filter then applies. Override the model at runtime through that filter; change the saved default through the option.
Alerts
Section titled “Alerts”| Hook | Returns |
|---|---|
wcbp_alert_dispatch_channels |
array - map of channel slug to callable( $alert, $job_ids ). The built-in email channel is present by default. Add your own channel, for example Slack or SMS. |
wcbp_alerts_notify_on_import |
bool - whether an imported job sends instant alert emails like a fresh posting (default false). Args: $notify, $job_id. Return true to send alerts for imported jobs. |
Credits SDK
Section titled “Credits SDK”| Hook | Returns |
|---|---|
wcbp_consumer_cost |
int - actual credits charged for a consumer. Args: $base_cost, $user_id, $item_id, $board_id, $consumer_slug. Tier-pricing happens here (e.g. BpTieredCreditCost). |
Kanban / pipeline
Section titled “Kanban / pipeline”| Hook | Returns |
|---|---|
wcbp_kanban_card_columns |
array - the column array that GET /jobs/{id}/kanban returns, before it is sent. Args: $columns, $job_id. Add columns such as archived or on-hold, or annotate existing ones. |
wcbp_kanban_include_unassigned |
bool - whether applications with no stage are folded into the first column (default true). Args: $include, $job_id, $board_id. |
wcbp_pipeline_board_for_job |
int - the board whose stages a job’s pipeline uses. Args: $board_id, $job_id. Lets a job have a dedicated pipeline without changing where it is listed. |
wcbp_default_pipeline_stages |
array - the stage rows seeded on a new board (each has a terminal_outcome of empty, hired or rejected). Return an empty array to skip seeding. Args: $stages, $board_id. |
wcbp_kanban_stage_limit |
int - cards fetched per stage per page on the Kanban board (default 25, clamped to 1-100). |
Maps and geocoding
Section titled “Maps and geocoding”| Hook | Returns |
|---|---|
wcbp_geocode_rate_limit |
int - uncached place lookups one IP address may make per hour through GET /geocode (default 30, 0 turns the limit off). |
wcbp_geocode_backfill_batch |
int - rows geocoded per background pass (default 25, clamped to 1-100). |
wcbp_geocode_throttle_us |
int - pause in microseconds between two backfill lookups (default 1100000, 1.1 seconds). |
wcbp_non_geographic_location_terms |
array - lowercase location values never sent to the geocoder (default: remote, anywhere, worldwide, hybrid, other, work from home, wfh). |
| Hook | Returns |
|---|---|
wcbp_pwa_manifest |
array - the PWA manifest before it is served at /wcb-manifest.json |
wcbp_pwa_host_app_active |
bool - whether another plugin’s app should carry the job board, so Career Board registers no manifest or worker. Default is whether BuddyNext’s app is on. Arg: $active. See PWA. |
Resume builder
Section titled “Resume builder”| Hook | Returns |
|---|---|
wcbp_resume_groups |
array - the resume-form field groups (Personal, Experience, Education, Skills, etc.) |
wcbp_resume_textarea_fields |
array - fields rendered as textareas vs single-line inputs |
wcbp_resume_checkbox_fields |
array - fields rendered as checkboxes |
wcbp_resume_date_fields |
array - fields formatted as date inputs |
wcbp_resume_proficiency_scale |
array of {value, percent} - the skill/language proficiency level table for a repeater group. Args: $scale, $group_key. Drives both the input dropdown values and the resume-single progress bar. |
wcbp_resume_experience_bands |
array of {slug, label, min, max} - the years-of-experience band table used to resolve a candidate’s experience-level slug. |
wcbp_resume_primary_fields |
array - the field keys shown on each resume section’s compact card (e.g. experience => [job_title, company]), before the first-2-fields fallback. Rendered in blocks/resume-builder/render.php. |
wcbp_resume_schema |
array - the resume schema (group key to label and field descriptors) that Pro builds for API clients. Arg: $schema. |
wcbp_resume_field_label |
string - override the label of a field. Args: $label, $field. |
wcbp_resume_pdf_renderer |
callable or null - return a callable ( string $html, int $post_id ) that returns the PDF bytes to replace the built-in DomPDF renderer. Args: $renderer, $post_id. |
Pro also extends these Free filters:
| Hook | What Pro returns |
|---|---|
wcb_rest_prepare_board |
Adds Pro-specific board metadata to the boards response. |
wcb_rest_prepare_board_stage |
Pipeline-stage data shape. |
wcb_rest_prepare_notification |
Notifications bell response shape. |
wcb_rest_prepare_resume |
Resume profile shape. Args: $data, $resume, $request, $context (single, list, create, save or pdf_replace). |
wcb_job_form_fields |
Injects custom job field groups (field builder). |
wcb_company_form_fields |
Injects custom company field groups. |
wcb_candidate_form_fields |
Injects custom candidate field groups. |
wcb_resume_form_fields |
Injects custom resume field groups. |
wcb_resume_form_initial_state |
array - the resume builder’s initial Interactivity-API state. Args: $state, $resume_id. Extend for a custom section’s state keys bound by a wcb_resume_form_fields field renderer. |
wcb_resume_form_simple_initial_state |
array - the quick resume form’s initial Interactivity-API state. Args: $state, $attributes (block attributes, not a resume id - the simple form can render for a not-yet-created resume). |
wcb_board_options_for_employer |
Restricts the board picker to the employer’s BuddyPress groups. |
Per-board credit cost is not a Free filter. The cost is resolved inside Pro’s SDK consumer
costcallback fromBoardSettings::get()and then run throughwcbp_consumer_cost.
Free filters Pro answers or fires
Section titled “Free filters Pro answers or fires”Free declares these filters. Pro answers them so Free features light up.
| Hook | Args | What Pro does |
|---|---|---|
wcb_employer_credit_has_history |
$has, $user_id |
Returns true when the employer has any row in the credit ledger. Free uses it to show the low-balance warning only to employers who have held credits. |
wcb_pro_active, wcb_pro_licensed, wcb_pro_version |
$default |
Report that Pro is installed, whether the license is valid, and the Pro version. |
wcb_pro_alerts_enabled, wcb_pro_resumes_enabled, wcb_pro_ai_enabled |
$default |
Report which Pro modules are present. |
wcb_job_payment |
$paid, $job_id, $event |
Free-owned filter that collects the price when an employer acts on a job. $event is create, resubmit, republish, board_change or feature. Pro’s JobCharge answers it by holding or charging credits and returns true or a WP_Error (a 402 when the balance is short). Pro takes the hold inside this filter, so a callback that runs this filter or publishes or rejects a job changes the employer’s balance: a job is held on submit, spent when it goes live, and refunded when it is rejected, trashed or deleted before then. |
wcb_app_enabled |
$enabled |
True only when Pro is active and the license is valid. This gates the mobile app connection only, not the web features. |
wcb_job_pipeline_url |
$url, $job_id |
Returns the Hiring Pipeline page with ?job=ID. Free uses it for the Pipeline button on employer job rows. |
wcb_community_notification_types |
$types |
Adds Pro’s own notification type. The shared types come from Free. |
wcb_email_announces_notification |
$announce, $email_id, $user_id |
Stops Pro emails the bell already announces from announcing a second time. |
wcb_resume_pdf_attachment_id |
$attachment_id, $resume_id, $user_id |
Builds and caches a PDF of a structured resume so a candidate can apply in one tap. |
wcb_page_definitions, wcb_settings_schema, wcb_settings_tabs |
array | Add the Hiring Pipeline, Job Map and Find Candidates pages, Pro settings, and Pro settings tabs. |
wcb_can_browse_candidates |
$can, $user_id, $level |
Fired by Pro. Change who may browse the candidate directory. $level is the setting: public, members or approved. |
wcb_can_view_resume_profile |
$can, $user_id, $level |
Fired by Pro. Change who may open a single resume. |
wcb_is_approved_employer |
$approved, $user_id |
Fired by Pro. Decide who counts as an approved employer for the approved level. |
Community notification contract
Section titled “Community notification contract”Every bell notification Pro records fires wcb_notification_created with two arguments: the original payload array and the community notification contract (or null when the row is admin-only). A notification center such as BuddyNext listens with accepted_args = 2. The contract fields and the builder are documented in the Free hooks reference under “Community notification contract”. A listener registered with one argument, like Pro’s own push module, still works.
Hooks that do not exist
Section titled “Hooks that do not exist”wcb_featured_upgrade_requested,_completedand_failedare not fired anywhere in Pro. Pro charges the featured upgrade itself through its job charge code. Third-party code that wants the credits SDK to hold, deduct or refund for its own consumer defines its own hook names; see Credits SDK.
Push notifications
Section titled “Push notifications”Native (Expo) push, in modules/push/class-push-module.php,
does not add a new hook. PushModule::boot() consumes the
existing wcb_notification_created action - the same event the
in-app notification bell listens to - and fans each payload out to
the user’s registered Expo devices via the shared AsyncScheduler.
There is one notification event and one source of truth; a site
adding a channel doesn’t need to learn a push-specific hook, only
wcb_notification_created.
Device registration/unregistration is REST-only, not hook-based - see
POST/DELETE /wcb/v1/push/register-device in
02-extending-free.md. PushModule exposes two
static helpers other Pro code can call directly:
PushModule::register_device( $user_id, $token, $platform, $device_name )
and PushModule::unregister_device( $token ).
Listening patterns
Section titled “Listening patterns”Send a Slack message when a card is moved to Hired
Section titled “Send a Slack message when a card is moved to Hired”wcb_application_status_changed fires with
($app_id, $old_status, $new_status, $reason, $by). Free fires it, and
Pro triggers it when a card lands in a stage with the Hired or Rejected outcome:
add_action( 'wcb_application_status_changed', function ( $app_id, $old_status, $new_status ) { if ( 'hired' !== $new_status ) { return; } $job_id = (int) get_post_meta( $app_id, '_wcb_job_id', true ); $job_title = get_the_title( $job_id ); wp_remote_post( SLACK_WEBHOOK, array( 'body' => wp_json_encode( array( 'text' => "Hired: {$job_title}" ) ), 'headers' => array( 'Content-Type' => 'application/json' ), ));}, 10, 3 );Add a custom group to the resume builder
Section titled “Add a custom group to the resume builder”add_filter( 'wcbp_resume_groups', function ( $groups ) { $groups['portfolio'] = array( 'label' => __( 'Portfolio links', 'my-addon' ), 'fields' => array( 'github' => array( 'type' => 'url', 'label' => 'GitHub' ), 'linkedin' => array( 'type' => 'url', 'label' => 'LinkedIn' ), 'dribbble' => array( 'type' => 'url', 'label' => 'Dribbble' ), ), ); return $groups;});Notify an employer when a stale credit hold auto-refunds
Section titled “Notify an employer when a stale credit hold auto-refunds”wcbp_credit_hold_reconciled fires once per orphaned hold the daily
reconciler cron refunds (a hold left open more than 24h with no
matching deduction or refund - typically a crashed request):
add_action( 'wcbp_credit_hold_reconciled', function ( $employer_id, $post_id, $amount, $orphan ) { wp_mail( get_userdata( $employer_id )->user_email, __( 'Credits refunded for an interrupted job post', 'my-addon' ), sprintf( '%d credits were auto-refunded for job #%d.', $amount, $post_id ) );}, 10, 4 );Tier the credit cost by user role
Section titled “Tier the credit cost by user role”add_filter( 'wcbp_consumer_cost', function ( $cost, $user_id, $item_id, $board_id, $consumer ) { // 'my_pro_tier_check' stands for your own membership test. if ( 'job_post' === $consumer && my_pro_tier_check( $user_id ) ) { return max( 0, (int) ( $cost / 2 ) ); // 50% off for premium employers } return $cost;}, 20, 5 );How to confirm an arg signature
Section titled “How to confirm an arg signature”grep -rn "do_action\\s*(\\s*'wcbp_credit_consumed'" wp-content/plugins/wp-career-board-pro/The result shows the file where Pro fires the hook. Read the lines around it for the parameter shapes.
Related
Section titled “Related”- Free hooks reference: The Free developer guide, page “Hooks reference”
- Credits SDK adapters: 04-credits-sdk.md
- The Free/Pro coupling contract: 02-extending-free.md

