Using the $bright PHP object to call the Bright API
Bright PHP API Reference
This document describes how to obtain the $bright object in WordPress, authenticate against the Bright server, and call the Bright API using callApi() and callV3Api().
It covers the WordPress connector layer (the $args model, access modes, response handling, and curl metadata). For field-by-field definitions of individual API controllers, see the Bright API documentation.
Prerequisites
Use this approach when you need server-side PHP access to Bright from:
- Custom theme or plugin code
- WooCommerce hooks
- Bright template extensions
- WP-CLI or admin scripts
Requirements:
| Requirement | Notes |
|---|---|
PHP curl extension |
Without it, $bright->successfullyInitialized is false and API calls will not work |
| Bright plugin has been configured | WP Site Options are created: bright_api_url, bright_realm_guid, bright_secret_key |
| Optional v3 URL | bright_api_v3_url — if empty, v3 root is derived from the v2 URL (/v2 → /v3) |
| Optional anonymous key | bright_anonymous_api_key — for unauthenticated (user ID 0) requests. Set in the WP Admin Console Bright settings |
Obtaining $bright
$bright is a local variable name, not a WordPress global and is an instantiation of the Bright Singleton pattern (see PHP Singleton explanation). The standard pattern is:
$bright = \Bright\Wordpress::getInstance();
Singleton and class hierarchy
Bright\WordpressextendsBright\BaseextendsBright\SingletongetInstance()creates one instance per request (lazy singleton)- Never instantiate
Bright\Basedirectly
On first getInstance():
- Constructor runs
getOptions()and loadsapiRoot,realmGuid,realmSecretKey, SCORM Cloud keys from WordPress options - If
curl_initis missing,successfullyInitializedis set tofalseandinitializationErrordescribes the problem
$bright = \Bright\Wordpress::getInstance();
if (!$bright->successfullyInitialized) {
error_log($bright->initializationError);
return;
}
Other web stacks
If you maintain a non-WordPress Bright connector, brightClass() can return a different class name (for example \Bright\Drupal). The default is \Bright\Wordpress.
Authentication
Most callApi() calls use the default access mode accessToken, which requires $bright->accessToken to be set. If it is empty, callApi() returns null immediately (no HTTP request).
When authentication happens automatically
On a normal front-end page request, the plugin runs doHeader(), which:
- Sets the current WordPress user via
setCurrentUser() - Calls
getAuthenticationCodeForUser()to obtain or restore an access token
In that context you can often call callApi() without extra setup, as long as the visitor is logged in (or anonymous access is configured).
The WordPress Action Workflow that Calls doHeader()
The Bright plugin integrates with WordPress using standard WP action hooks to ensure authentication and environment setup occur early in the page load cycle. The principal initialization occurs in the doHeader() method of the Bright connector class.
When is doHeader() called?
doHeader()is hooked into thewpaction, which fires after the query variables are set and just before output starts.- This ensures that authentication and connection setup are ready before any content is rendered (including shortcodes, templates, etc).
Example from plugin bootstrap:
add_action('wp', array(\Bright\Wordpress::getInstance(), 'doHeader'));
Workflow Steps
- WordPress loads and triggers its lifecycle hooks.
- On every page request (unless in admin or REST context), the Bright plugin's bootstrap code hooks
doHeader()to thewpaction. - When the
wpaction fires:doHeader()sets upBright\Wordpress:- Loads/caches WordPress user into the Bright OOP context.
- Attempts to authenticate (sets
accessTokenfor the user if needed). - Ensures all critical options (API URL, realm credentials, etc.) are loaded and validated.
- After this, your code, theme files, or shortcodes may safely use
$bright = \Bright\Wordpress::getInstance()and assume authentication is handled.
Where to find this in code
- This hook is typically established in the main plugin file or an included bootstrap module within the plugin directory, for example:
// In bright-wordpress/bright.php or similar:
add_action('wp', function() {
\Bright\Wordpress::getInstance()->doHeader();
});
- See also the companion hooks for
admin_initin the admin context, if relevant.
Summary Table
| WP Hook | Method | Purpose |
|---|---|---|
wp |
doHeader() |
Authenticates user and initializes Bright for all front-end page loads |
init |
Sometimes used | Occasionally used for earlier setup of plugin text domains or supporting structures |
shortcode processing |
after doHeader() | Shortcodes and API calls can rely on $bright having access/authentication initialized |
In short:
If you call plugin APIs on a normal page, authentication/setup has already occurred because doHeader() runs on wp. This is why in normal theme/template code you do not need to manually call setCurrentUser() and getAuthenticationCodeForUser().
For custom workflows—before wp fires (early/exotic scripts, AJAX, admin, CLI)—you must handle authentication manually as referenced above.
When you must authenticate manually
Use this path in custom code that runs before doHeader(), in admin/CLI contexts, or when switching users:
$bright = \Bright\Wordpress::getInstance();
$user = wp_get_current_user();
$bright->setCurrentUser($user);
$bright->getAuthenticationCodeForUser($user);
if (empty($bright->accessToken)) {
// Cannot call accessToken-mode APIs
return;
}
Or combine set + authenticate:
$bright->setAndAuthenticateCurrentUser($user);
or even
$bright->setAndAuthenticateCurrentUser(wp_get_current_user());
Token acquisition
getAuthenticationCodeForUser() POSTs to {apiRoot}/api_key.json with realm credentials and the user's email. On success it sets:
| Property | Source |
|---|---|
$bright->accessToken |
access_token from JSON response |
$bright->accessTokenExpiration |
expires_at |
$bright->realmId |
realm_id |
Tokens are cached in per-user meta: bright_cached_api_key, bright_cached_api_key_expiration, bright_cached_api_key_url, bright_cached_realm_id.
Anonymous users
If the current user has ID === 0 and bright_anonymous_api_key is configured, that static key is used as accessToken without a server round-trip.
Re-authenticate after settings change
$bright->reset(); // clears token, reloads options, re-authenticates current user
One-off token for an email (realm mode via callApi)
$token = $bright->getAuthenticationCodeForEmail('learner@example.com');
// Internally: callApi('api_key', method POST, realm params, success callback)
callApi() overview
$result = $bright->callApi($apiController, $args);
| Parameter | Description |
|---|---|
$apiController |
API path segment before .json (e.g. 'course', 'stored_query/run', 'invitation/redemptions') |
$args |
Associative array of options (see full model below) |
URL built: <code class="kb-btn">apiRoot}/{apiController}.json?{query</code>
- GET (default): all
paramsgo in the query string - POST / PUT:
paramsare sent as the request body; query string is empty
callApi() — full $args model
| Key | Default | Behavior |
|---|---|---|
accessMode |
'accessToken' |
'accessToken' merges accessToken into params; 'realm' merges realm_guid and realm_secret_key from plugin options. See Access modes. |
params |
[] |
Query string (GET) or POST/PUT body. Auth fields are merged automatically per accessMode. |
method |
(GET) | Set to 'POST' or 'PUT' to change HTTP method. |
raw |
unset → decode | If the key exists (isset($args['raw'])), the response body is returned as a string. If unset, json_decode() is applied. raw => false still returns a string because only key presence is checked. |
encode |
— | Array of param names to json_encode before send (e.g. nested structures for invitations). |
success |
— | Callable function ($rsp, $curlInfo, $curlError). Return value becomes the callApi() return. Runs when body length > 1. |
failure |
— | Same signature; runs when body is empty or length ≤ 1. |
errorMsgs |
401, 404 messages |
Map HTTP status code → message string. Passed to curl(); may write HTML error blocks via writeToPage(). |
suppressErrorBlock |
false | If true, suppresses generic Bright HTML error blocks on curl/HTTP errors. |
dontcheckcache |
false | Skip reading from the per-request in-memory API cache. |
dontcacheresult |
false | Do not store this response in the cache. |
removecacheresult |
false | Delete the matching cache entry after the call (use before updates). |
apiRoot |
$bright->apiRoot |
Override API base URL. Set automatically by callV3Api(). |
Return semantics
| Condition | Return |
|---|---|
accessMode === 'accessToken' and empty accessToken |
null (no request) |
| Response body empty or length ≤ 1 | null, or failure callback result |
Success, no success callback |
Decoded JSON (stdClass / arrays) or raw string if raw key set |
Success, with success callback |
Whatever the callback returns |
Failure, with failure callback |
Whatever the callback returns |
Important: json_decode() is called without the true flag, so JSON objects become stdClass, not associative arrays.
Access modes
Only two values are implemented in callApi():
accessToken (default)
Merges the current user's token into params:
'accessToken' => $bright->accessToken
Use for: learner-scoped data — courses, registrations, stored queries run as the logged-in user.
$bright = \Bright\Wordpress::getInstance();
$rows = $bright->callApi('stored_query/run', array(
'params' => array(
'name' => 'getLicenseKeysForUser',
'host_url' => get_site_url(),
'query_scope' => 'bright',
),
));
realm
Merges realm credentials from plugin settings:
'realm_guid' => $bright->realmGuid,
'realm_secret_key' => $bright->realmSecretKey
Use for: server-side / admin operations — creating invitations, realm custom data, fetching registration by GUID without a user token, WooCommerce license-key flows.
$bright->callApi('invitation/add_learners', array(
'accessMode' => 'realm',
'params' => array(
'name' => $invitationName,
'learners' => \Bright\Base::encodeJson(array($email)),
),
));
Pitfall: invalid accessMode
Any value other than 'accessToken' or 'realm' skips auth injection. Requests will likely return 401. Always pass exactly one of the two supported strings.
Raw vs non-raw responses
Non-raw (default)
JSON is decoded automatically:
$course = $bright->getCourseDataByGuid($guid);
// $course is a stdClass with properties like course_guid, title, ...
List endpoints return a JSON array, which becomes a PHP array of stdClass objects:
$courses = $bright->callApi('course');
// array of stdClass
Raw
Pass 'raw' => true (or any value — only key presence matters):
$json = $bright->callApi('stored_query/run', array(
'params' => array(
'name' => 'bright_completion_matrix',
'host_url' => get_site_url(),
'query_scope' => 'bright',
),
'raw' => true,
));
// $json is a string — embed in a page or pass to JavaScript
For associative arrays after a raw call:
$data = json_decode($json, true);
callV3Api()
$result = $bright->callV3Api($apiController, $args);
This is a thin wrapper: it sets $args['apiRoot'] from getBrightV3ApiRoot() and calls callApi(). All $args keys behave the same.
V3 URL resolution
- If
bright_api_v3_urlis set in plugin options, use that (trimmed, no trailing slash) - Else if v2 root ends with
/v2, replace with/v3 - Else append
/v3to the v2 root
Example: http://localhost:3000/bright/api/v2 → http://localhost:3000/bright/api/v3
getRedemptionsAvailableFor() routing helper
This helper picks v2 vs v3 automatically:
| Params | API used |
|---|---|
invitation_name set |
v2 stored_query/run with name=redemptions_available_for |
order_id or order_ids |
v3 invitation/redemptions via callV3Api |
Default for this helper is 'raw' => true unless you override in $args.
$json = $bright->getRedemptionsAvailableFor(array(
'accessMode' => 'realm',
'params' => array('order_ids' => '670,684'),
));
$body = json_decode($json, true);
Example response shapes
Controller responses are defined by the Bright server. Below are representative shapes as seen through the WordPress connector.
v2 — single course (course with course_guid)
Non-raw; decoded object (from integration tests):
{
"course_guid": "PSOAS_SCORM_12-17318b2dc9-7128-4e7e-b7e3-fa591b7fc446",
"title": "The Role of the Psoas in Yoga Asana and Postural Health"
}
In PHP: $course->course_guid, $course->title.
v2 — course list (course without filter)
Returns an array of course objects.
v2 — registration (registration)
Often an array; helper methods return the first element:
$reg = $bright->getRegistrationDataForCourse($courseGuid);
// stdClass or '{}' string on 404
Example registration fields: type, course_guid, registration_guid, registration_guids.
v2 — stored query (stored_query/run)
Shape depends on the query name. Reports typically use raw => true and return a JSON string for templates or DataTables. See also Bright Scoped Stored Queries API Reference and your team's Rails stored-query docs for query parameters.
v3 — invitation/redemptions
When decoded with json_decode($raw, true):
{
"results": [
{
"license_key": "13708-14097-56871-91719-163f07ce-c3270a5d",
"order_id": 670,
"created": "2024-06-01 10:15:00",
"seats_available": 5,
"seats_used": 2,
"title": "Example Course A"
}
],
"meta": {
"requested_order_ids": [670, 684],
"returned_order_ids": [670, 684],
"skipped_order_ids": [],
"skipped_reason": null
}
}
Auth — api_key POST response
Used internally by getAuthenticationCodeForUser() (not typically called via callApi for page auth):
{
"access_token": "...",
"expires_at": "...",
"realm_id": 123
}
Invitation POST response
Realm-mode calls such as addLearnerToInvitation may return an object with messages or error — inspect $bright->curlHttpCode alongside the decoded body.
Success and failure callbacks
Callbacks receive three arguments: $rsp, $curlInfo, $curlError.
Success callback — transform return value
$title = $bright->getCourseDataByGuid($guid, array(
'success' => function ($rsp, $curlInfo, $curlError) {
return $rsp->title;
},
));
// $title is a string
Failure callback — branch on HTTP status
$bright->callApi('stored_query/run', array(
'params' => array(
'name' => 'invitation_completion_matrix',
'invitation_name' => $name,
'host_url' => get_site_url(),
'query_scope' => 'bright',
),
'suppressErrorBlock' => true,
'raw' => true,
'failure' => function ($rsp, $curlInfo, $curlError) {
if ($curlInfo['http_code'] == 401) {
_e('You do not have permission to view this report.');
}
return null;
},
));
Curl metadata
callApi() does not return curl data. After every call (including cache hits), inspect properties on $bright:
| Property | Set from | Typical use |
|---|---|---|
$bright->curlHttpCode |
$bright->curlInfo['http_code'] |
Branch on 200, 404, 500 |
$bright->curlError |
curl_error() |
Transport-level failures |
$bright->curlInfo |
curl_getinfo() |
Full metadata array |
Example: HTTP status after invitation
$ret = $bright->addLearnerToInvitation($email, $licenseKey, array(
'errorMsgs' => array(),
'params' => array('nodelay' => true),
));
if ($bright->curlHttpCode == 404) {
// license key not found
} elseif ($bright->curlHttpCode == 200) {
// success — check $ret->messages
} else {
// other error — may use $ret->error
}
Notable curlInfo keys
After a call, $bright->curlInfo may include:
| Key | Meaning |
|---|---|
http_code |
HTTP status (mirrored in curlHttpCode) |
url |
Request URL |
total_time |
Total time in seconds |
content_type |
Response Content-Type |
size_download |
Bytes downloaded |
curlErrorMsg()
Returns a human-readable message. Do not use this to detect errors — use $bright->curlHttpCode and $bright->curlError instead.
Per-request API cache
Identical callApi arguments (URL + sorted params) are cached in memory for the duration of the request. On cache hit, curlInfo and curlError are restored from cache.
The page footer may expose stats via JavaScript:
Bright.cacheData = { "num_cache_hits": N, "num_cache_misses": M, "total_time": T };
Cookbook
1. Stored query as logged-in user
$bright = \Bright\Wordpress::getInstance();
// Assumes doHeader() already ran, or authenticate manually
$rows = $bright->callApi('stored_query/run', array(
'params' => array(
'name' => 'getLicenseKeysForUser',
'host_url' => get_site_url(),
'query_scope' => 'bright',
),
));
2. Stored query JSON for a template (raw)
$data = $bright->callApi('stored_query/run', array(
'params' => $attr,
'raw' => true,
));
3. Realm-mode POST — add learner to invitation
Handled by addLearnerToInvitation(); equivalent direct call:
$bright->callApi('invitation/add_learners', array(
'accessMode' => 'realm',
'params' => array(
'name' => $invitationName,
'learners' => \Bright\Base::encodeJson(array($learnerEmail)),
),
));
4. Direct v3 redemptions
$raw = $bright->callV3Api('invitation/redemptions', array(
'accessMode' => 'realm',
'params' => array('order_ids' => '670,684'),
'raw' => true,
));
$body = json_decode($raw, true);
5. getRedemptionsAvailableFor with order IDs
$raw = $bright->getRedemptionsAvailableFor(array(
'accessMode' => 'realm',
'params' => array('order_ids' => '670,684'),
));
6. POST with encoded params — create invitation
$bright->callApi('invitation', array(
'accessMode' => 'realm',
'method' => 'POST',
'encode' => array('course_guids', 'license_data', 'custom'),
'params' => array(/* invitation fields */),
));
Or use $bright->createInvitation($args) which sets method and encode for you.
7. Fetch API key for an email (POST)
$token = $bright->callApi('api_key', array(
'method' => 'POST',
'params' => array(
'realm_guid' => $bright->realmGuid,
'realm_secret_key' => $bright->realmSecretKey,
'user_email' => $email,
),
'success' => function ($rsp) {
return $rsp->access_token;
},
));
8. Inspect HTTP code after any call
$result = $bright->callApi('course', array('params' => array('course_guid' => $guid)));
$code = $bright->curlHttpCode;
9. Cache control before an update
$bright->callApi('realm/' . $bright->realmId . '/write_custom_key', array(
'accessMode' => 'realm',
'method' => 'POST',
'removecacheresult' => true,
'dontcheckcache' => true,
'params' => array(/* ... */),
));
Appendix — deprecated globals and functions
Pre–Bright 8.0 code may use global wrappers from php-connect/wp-deprecation.php. Prefer the singleton pattern for new code.
| Deprecated | Replacement |
|---|---|
bright_curl($url, $method, $data) |
$bright = \Bright\Wordpress::getInstance(); then $bright->curl($url, array('method' => $method, 'params' => $data)) |
Global $bright_curl_error |
$bright->curlError (set by bright_curl() for backward compatibility) |
Global $bright_curl_info |
$bright->curlInfo |
bright_curl_error() |
$bright->curlErrorMsg() — display only, not for error detection |
See php-connect/deprecation-list.md for the full migration list.
Related documentation
In this plugin
| Document | Topic |
|---|---|
| bright-shortcode-reference.md | [bright] shortcode attributes |
| php-connect/filter-reference.md | WordPress filters and actions |
| php-connect/attribute-reference.md | Shortcode attribute details |
| php-connect/deprecation-list.md | Deprecated functions |
| DEVELOPMENT.md | Local development and debugging |
External
| Resource | Topic |
|---|---|
| bright-api-doc | v2 API controllers, request/response fields |
| v2 API controller reference | Realm endpoints (e.g. realm_user/gcustom) |
Bright server (Rails)
If your team maintains scoped stored-query documentation on the Rails app, use that for query name, query_scope, and parameter definitions. The WordPress plugin only passes those through via params on stored_query/run.
Quick reference
// 1. Get instance
$bright = \Bright\Wordpress::getInstance();
// 2. Authenticate (if needed)
$bright->setCurrentUser(wp_get_current_user());
$bright->getAuthenticationCodeForUser();
// 3. Call API
$result = $bright->callApi('course', array(
'params' => array('course_guid' => $guid),
));
// 4. Check HTTP status (not returned from callApi)
if ($bright->curlHttpCode !== 200) {
error_log($bright->curlErrorMsg());
}
// v3
$raw = $bright->callV3Api('invitation/redemptions', array(
'accessMode' => 'realm',
'params' => array('order_ids' => '123'),
'raw' => true,
));

