Goals
Goals let you track conversions in Burst Statistics — clicks, page visits, hook triggers, and more. Each goal stores its own conversion data so you can measure performance over a defined date range.
Overview
A goal is a database record in {prefix}_burst_goals. When a visitor completes a goal, a row is written to {prefix}_burst_goal_statistics linking the pageview statistic to the goal. Burst ships two goal-processing paths:
- Client-side — the browser tracking script detects the conversion (click, visit) and reports it in the tracking payload.
- Server-side — PHP detects the conversion (a WordPress action hook fires) and writes the statistic directly.
Goals are represented by the Burst\Frontend\Goals\Goal class and managed in bulk via Burst\Frontend\Goals\Goals.
Goal Object
The Burst\Frontend\Goals\Goal class represents a single goal. Properties are read/write via magic __get / __set.
| Property | Type | Default | Description |
|---|---|---|---|
id | int | 0 | Database primary key (ID column). |
title | string | '' | Human-readable goal name. Defaults to "New goal" when empty. |
type | string | 'clicks' | Goal type slug. See Goal Types. |
status | string | 'inactive' | 'active' or 'inactive'. |
server_side | bool | false | Set automatically to true when type is 'hook' or 'visits'. Derived at load time — not stored as a separate column. |
url | string | '*' | Raw URL value stored in the database. '*' means site-wide. |
page_or_website | string | 'website' | Derived from url. 'website' when url === '*'; 'page' otherwise. |
specific_page | string | '' | Relative URL used when page_or_website === 'page'. Derived from url. |
conversion_metric | string | 'visitors' | How conversions are counted. |
selector | string | '' | CSS selector for click-type goals. |
hook | string | '' | WordPress action name for hook-type goals. |
date_start | int | — | Unix timestamp when the goal became active. Reset each time status changes to 'active', or on first creation. |
date_end | int | 0 | Unix timestamp when tracking ended. 0 means still running. |
date_created | int | 0 | Unix timestamp of first insertion. |
Deprecated Properties
The following properties were deprecated in v2.0.0 and may be removed in a future release. Do not use them in new code.
| Property | Type | Replacement |
|---|---|---|
attribute | ?string | Use selector instead. |
attribute_value | ?string | Use selector instead. |
Goal Types
Goal types are registered through the field definitions and can be extended with the burst_goal_types filter.
| Type | Tracking path | server_side | Description |
|---|---|---|---|
clicks | Client-side | false | Fires when a visitor clicks an element matching selector. |
visits | Server-side | true | Fires when a visitor lands on the target URL. |
hook | Server-side | true | Fires when a specified WordPress action hook executes. |
server_side is derived automatically in Goal::get():
$this->server_side = $this->type === 'hook' || $this->type === 'visits';
Free vs Pro: Goal Limits
Pro
The Pro version allows unlimited goals. The free version permits only one goal at a time. If a goal already exists in the database, Goal::save() silently returns false for any new insert on the free version. Learn more about goal conversion tracking
Tracking Lifecycle
Client-side goals (e.g. clicks)
- The visitor interacts with an element matching the goal's
selector. - The frontend goals script appends the goal ID to the
completed_goalsarray in the tracking payload. - The tracking endpoint receives the payload and records the conversion in
{prefix}_burst_goal_statistics.
Server-side goals — hook type
- During the WordPress
initaction,Goals_Tracker::add_dynamic_hooks()reads every activehook-type goal and registers a WordPress action for each goal'shookproperty. - When that action fires,
Goals_Tracker::handle_hook( $hook_name )runs:- Reads the
burst_uidcookie to identify the visitor. - If no
burst_uidis present, the conversion is not recorded. - Retrieves the visitor's most recent statistic row via
get_last_user_statistic(). - If the goal is scoped to a specific page (
page_or_website === 'page'), checks thatspecific_pageappears in the storedpage_url + parametersstring. - Calls
create_goal_statistic()to write the conversion.
- Reads the
// Trigger a custom hook-type goal.
// 1. In Burst, create a goal with type = 'hook' and hook = 'my_plugin_form_submitted'.
// 2. Fire the action from your plugin:
do_action( 'my_plugin_form_submitted' );
// Goals_Tracker picks up the action and records the conversion
// for the currently identified visitor.
Hook-type goals rely on the burst_uid cookie being set by a prior client-side pageview. If the cookie is absent (e.g. the form was submitted without a preceding tracked pageview), the conversion will not be recorded.
Database Tables
| Table | Purpose |
|---|---|
{prefix}_burst_goals | One row per goal; stores all goal configuration. |
{prefix}_burst_goal_statistics | Many-to-many join between statistic rows and goal IDs. All rows for a goal are deleted when the goal is deleted. |
Tables are created via the burst_install_tables action. See burst_install_tables.
Goal Conversion Queries
Internally, Goal_Statistics::get_goal_completed_count_sql() builds the SQL used to count goal completions. As of v3.3.0, this query JOINs {prefix}_burst_sessions so that session-level attributes such as device_id are read from the sessions table rather than the statistics table.
Changed in v3.3.0: device_id (and the related browser_id, platform_id, browser_version_id, first_time_visit, and bounce columns) have moved from {prefix}_burst_statistics to {prefix}_burst_sessions. Any custom SQL that queries goal conversions and references these columns by statistics.device_id (or without a table qualifier) must be updated to JOIN {prefix}_burst_sessions and reference sessions.device_id instead.
The generated SQL now takes the following form:
// Simplified representation of the query produced by get_goal_completed_count_sql().
global $wpdb;
$sql = $wpdb->prepare(
"SELECT COUNT(DISTINCT statistics.uid) AS value
FROM {$wpdb->prefix}burst_statistics AS statistics
INNER JOIN {$wpdb->prefix}burst_goal_statistics AS goals
ON statistics.ID = goals.statistic_id
INNER JOIN {$wpdb->prefix}burst_sessions AS sessions
ON statistics.session_id = sessions.ID
WHERE goals.goal_id = %s
AND statistics.time > %s",
$goal_id,
$date_start
);
The device-breakdown query used to determine the best-performing device for a goal also references sessions.device_id:
// Pageviews per device — sessions JOIN required since device_id moved to burst_sessions.
$sql = $wpdb->prepare(
"SELECT COUNT(statistics.uid) AS value, sessions.device_id
FROM {$wpdb->prefix}burst_statistics AS statistics
INNER JOIN {$wpdb->prefix}burst_sessions AS sessions
ON statistics.session_id = sessions.ID
WHERE statistics.time > %s
GROUP BY sessions.device_id
ORDER BY value DESC
LIMIT 4",
$date_start
);
Predefined Goals
Integrations can register predefined goal templates. Goals::get_predefined_goals() collects the goals array from each registered integration and returns them as a flat list.
/**
* @param bool $skip_active_check Pass true to include goals from inactive integration plugins.
* @return array<int, array{
* id: string,
* type: string,
* description: string,
* status: string,
* server_side: bool,
* url: string,
* hook: string
* }>
*/
$predefined = burst_loader()->frontend->goals->get_predefined_goals();
By default only goals from active integration plugins are returned.
A predefined goal template can be saved with Goal::add_predefined( string $id ):
$goal = new \Burst\Frontend\Goals\Goal();
$new_id = $goal->add_predefined( 'woocommerce-purchase' );
// Returns the new goal ID on success, or 0 on failure.
add_predefined() sets status = 'active', conversion_metric = 'visitors', and url = '*' as defaults before calling save().
Pro
Predefined goals that depend on third-party plugin integrations are only surfaced when those plugins are active. Adding any goal requires the manage_burst_statistics capability. Upgrade to Burst Pro
Querying Goals
$goals = burst_loader()->frontend->goals->get_goals( [
'status' => 'active', // 'active', 'inactive', or 'all' (default)
'limit' => 10, // default: 9999
'offset' => 0, // default: 0
'orderby' => 'ID', // any column in burst_goals; default: 'ID'
'order' => 'ASC', // 'ASC' or 'DESC'; default: 'ASC'
'date_start' => strtotime( '-30 days' ), // Unix timestamp; -1 = no filter (default)
'date_end' => time(), // Unix timestamp; default: time()
] );
foreach ( $goals as $goal ) {
echo $goal->id . ': ' . $goal->title . ' (' . $goal->type . ')';
}
date_start and date_end filter on date_created. The orderby value is validated against the actual columns of burst_goals; unknown values fall back to 'ID'.
Saving and Deleting Goals
Creating a new goal
$goal = new \Burst\Frontend\Goals\Goal();
$goal->title = 'Newsletter signup';
$goal->type = 'clicks';
$goal->selector = '#newsletter-form .submit-btn';
$goal->status = 'active';
$success = $goal->save();
echo $goal->id; // populated after a successful insert
Updating an existing goal
$goal = new \Burst\Frontend\Goals\Goal( 42 );
$goal->status = 'inactive';
$goal->save();
Deleting a goal
$goal = new \Burst\Frontend\Goals\Goal( 42 );
$goal->delete(); // removes the goal row AND all burst_goal_statistics rows for this goal
Save behaviour notes
title,selector, andhookare sanitized withsanitize_text_field().urlis sanitized as a relative URL. Whenpage_or_website === 'website'the stored value is forced to'*'.server_sideis derived from the goal type definition — not settable by the caller.date_startis set totime()on first creation or wheneverstatuschanges to'active'.- Returns
trueon success,falseon failure (including exceeding the free-tier goal limit).
Hooks and Filters
burst_goal_types
Filter the available goal type definitions. Controls which types appear in the goal editor and are accepted by Goal::save().
Parameters:
| Parameter | Type | Description |
|---|---|---|
$types | array | Associative array of goal type definitions keyed by type slug. Each entry may include label, description, icon, and server_side. |
Example:
add_filter( 'burst_goal_types', function( array $types ): array {
$types['video_play'] = [
'label' => __( 'Video play', 'my-plugin' ),
'description' => __( 'Fires when a video starts playing.', 'my-plugin' ),
'server_side' => false,
];
return $types;
} );
burst_before_save_goals
Fires immediately before a goal is written to the database (both insert and update).
Parameters:
| Parameter | Type | Description |
|---|---|---|
$goal | \Burst\Frontend\Goals\Goal | The Goal object about to be saved. Public properties can be read or mutated. |
Example:
add_action( 'burst_before_save_goals', function( \Burst\Frontend\Goals\Goal $goal ): void {
if ( $goal->type === 'hook' && empty( $goal->hook ) ) {
$goal->hook = 'woocommerce_thankyou';
}
} );
burst_after_save_goals
Fires after a goal has been successfully saved and the object refreshed from the database. Does not fire when save() returns false.
Parameters:
| Parameter | Type | Description |
|---|---|---|
$goal | \Burst\Frontend\Goals\Goal | The saved Goal object with current database values, including the new id for inserts. |
Example:
add_action( 'burst_after_save_goals', function( \Burst\Frontend\Goals\Goal $goal ): void {
if ( $goal->status === 'active' ) {
my_crm_sync_goal( $goal->id, $goal->title );
}
} );
burst_install_tables
Action fired by the Burst installer to trigger database table creation. Goals hooks into this at priority 10 to create {prefix}_burst_goals.
Parameters: none.
Example:
// Force table creation, e.g. after a manual reset.
do_action( 'burst_install_tables' );