Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ jobs:
test -f release/hellotext-wordpress/hellotext.php
test -d release/hellotext-wordpress/src
test -f release/hellotext-wordpress/vendor/autoload.php
test -f release/hellotext-wordpress/assets/hellotext-service-worker.js
test -f release/hellotext-wordpress/assets/storefront.js

for path in \
release/hellotext-wordpress/tests \
Expand Down
129 changes: 71 additions & 58 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,9 @@ $response = Client::post(Constants::API_ENDPOINT_PROFILES, [
- `put(string $path, ?array $data = null): array`
- `delete(string $path, ?array $data = null): array`

##### `with_sufix(string $sufix = ''): self`
##### `api_url(): string`

Creates a client instance with a custom API suffix. Useful for testing.

**Example:**

```php
$client = Client::with_sufix('/v2');
```
Returns the Hellotext API URL: `https://api.hellotext.com`, or the `HELLOTEXT_API_URL` constant when it is defined.

## Event Tracking

Expand All @@ -105,7 +99,7 @@ Tracks customer activities and sends them to Hellotext.
public function __construct(?string $session = null)
```

Creates a new event tracker. If no session is provided, it attempts to retrieve it from the `hello_session` cookie.
Creates a new event tracker for the given session. Storefront events pass `Session::current()`; order and refund events pass `Session::for_order($order)`, because they also run from wp-admin and payment callbacks, where the browser cookie belongs to someone else.

#### Methods

Expand Down Expand Up @@ -305,39 +299,35 @@ $service->process();

### `Hellotext\Services\Session`

Manages session encryption and cookies.
Reads the `hello_session` cookie that Hellotext.js sets, and encrypts the copy stored on orders.

#### Static Methods

##### `create(): string`
##### `current(): ?string`

Creates a new session identifier.
The visitor's Hellotext.js session, or `null` when the cookie is missing.

**Returns:** UUID session string
##### `for_order(WC_Order $order): ?string`

##### `encrypt(string $session): string`
The session stored on the order at checkout, or `null` when there is none.

Encrypts a session string using AES-256-CBC.

##### `decrypt(string $encrypted_session): string`
##### `encrypt(?string $session): string`

Decrypts an encrypted session string.
Encrypts a session string using AES-256-CBC.

##### `set_cookie(string $session): void`
##### `decrypt(mixed $encrypted_session): string|false`

Sets the `hello_session` cookie with proper expiration and security flags.
Decrypts an encrypted session string. Returns `false` for empty or malformed values.

**Example:**

```php
use Hellotext\Services\Session;

$session = Session::create();
Session::set_cookie($session);
$order->update_meta_data('hellotext_session', Session::encrypt(Session::current()));
$order->save_meta_data();

// Later, encrypt for storage
$encrypted = Session::encrypt($session);
add_post_meta($order_id, 'hellotext_session', $encrypted);
$session = Session::for_order($order);
```

## Constants Reference
Expand All @@ -349,12 +339,12 @@ All plugin constants are centralized in this class.
#### API Configuration

```php
Constants::API_VERSION // 'v1'
Constants::API_URL // 'https://api.hellotext.com'
Constants::API_ENDPOINT_TRACK // '/v1/track/events'
Constants::API_ENDPOINT_PROFILES // '/profiles'
Constants::API_ENDPOINT_SESSIONS // '/sessions'
Constants::API_ENDPOINT_WEBCHATS // '/v1/wordpress/webchats'
Constants::API_ENDPOINT_PROFILES // '/v1/profiles'
Constants::API_ENDPOINT_SESSIONS // '/v1/sessions'
Constants::API_ENDPOINT_INTEGRATIONS_WOO // '/integrations/woo'
Constants::SDK_URL // Hellotext.js on jsDelivr, unversioned
```

#### Session & Encryption
Expand All @@ -369,16 +359,15 @@ Constants::SESSION_COOKIE_NAME // 'hello_session'
```php
Constants::OPTION_BUSINESS_ID // 'hellotext_business_id'
Constants::OPTION_ACCESS_TOKEN // 'hellotext_access_token'
Constants::OPTION_WEBCHAT_ID // 'hellotext_webchat_id'
Constants::OPTION_WEBCHAT_PLACEMENT // 'hellotext_webchat_placement'
Constants::OPTION_WEBCHAT_BEHAVIOUR // 'hellotext_webchat_behaviour'
Constants::OPTIONS // every option above plus the webchat options of earlier versions, removed on uninstall
```

#### User Meta Keys
#### Meta Keys

```php
Constants::META_PROFILE_ID // 'hellotext_profile_id'
Constants::META_SESSION // 'hellotext_session'
Constants::META_PROFILE_ID // 'hellotext_profile_id' (user)
Constants::META_SESSION // 'hellotext_session' (user and order)
Constants::META_ORDER_PLACED // 'hellotext_order_placed' (order): 'pending' after checkout, 'tracked' once order.placed is sent
```

#### Event Names
Expand All @@ -403,19 +392,26 @@ The plugin registers these WooCommerce and WordPress hooks:
| Hook | Handler | Purpose |
| --------------------------------------------- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `woocommerce_after_single_product` | `hellotext_product_viewed` | Track `product.viewed` |
| `woocommerce_after_cart` | `hellotext_trigger_cart_updated` | Compare current and previous cart state |
| `woocommerce_add_to_cart` | `hellotext_trigger_cart_updated` | Compare current and previous cart state |
| `woocommerce_cart_item_removed` | `hellotext_trigger_cart_updated` | Compare current and previous cart state |
| `woocommerce_after_cart_item_quantity_update` | `hellotext_trigger_cart_updated` | Compare current and previous cart state |
| `woocommerce_after_cart` | `hellotext_trigger_cart_updated` | Schedule a cart comparison at shutdown |
| `woocommerce_add_to_cart` | `hellotext_trigger_cart_updated` | Schedule a cart comparison at shutdown |
| `woocommerce_cart_item_removed` | `hellotext_trigger_cart_updated` | Schedule a cart comparison at shutdown |
| `woocommerce_after_cart_item_quantity_update` | `hellotext_trigger_cart_updated` | Schedule a cart comparison at shutdown |
| `shutdown` | `hellotext_cart_updated` | Track `cart.added` with the product's whole quantity in the cart, which Hellotext sets the line to, and `cart.removed` with the quantity removed, after WooCommerce recalculates totals. A Webchat card's addition carries its message as `source` |
| `woocommerce_cart_emptied` | `hellotext_reset_cart_snapshot` | Forget the cart snapshot and the tracked checkout so purchased items are not reported as removed and the next checkout is reported |
| `template_redirect` | `hellotext_cart_viewed` | Track `cart.viewed` on the cart page with the whole cart |
| `template_redirect` | `hellotext_checkout_started` | Track `checkout.started` on the checkout page, once per cart; not on the thank-you or payment pages |
| `template_redirect` | `hellotext_checkout_link` | `?hellotext_checkout=1&products=id:quantity,…`, the checkout link Hellotext sends stores older than WooCommerce 10.0: replace the cart with the products and open the checkout with the link's other parameters, or the page of a product that needs options |
| `woocommerce_applied_coupon` | `hellotext_coupon_redeemed` | Track valid `coupon.redeemed` events |
| `woocommerce_after_order_details` | `hellotext_order_placed` | Track `order.placed` and persist encrypted session metadata on the order; render-based hook, so duplicate prevention is required |
| `woocommerce_order_status_changed` | `track_order_status` | Track `order.confirmed`, `order.cancelled`, and `order.delivered` |
| `woocommerce_checkout_order_processed` | `hellotext_checkout_order_processed` | Classic checkout: store the encrypted session on the order and create the customer's profile |
| `woocommerce_store_api_checkout_order_processed` | `hellotext_capture_checkout` | Checkout block: store the encrypted session on the order and create the customer's profile |
| `woocommerce_thankyou` | `hellotext_thankyou` | Track `order.placed` once the order is paid or on hold |
| `woocommerce_order_status_changed` | `hellotext_order_status_changed` | Track `order.placed` if still pending (block themes, customers who never return from payment), then `order.confirmed`, `order.cancelled`, `order.delivered` |
| `woocommerce_order_refunded` | `hellotext_refund_created` | Track `refund.received` |
| `user_register` | `hellotext_user_registered` | Track customer registration/profile flow |
| `hellotext_woocommerce_cart_updated` | `hellotext_cart_updated` | Track `cart.added` and `cart.removed` |
| `update_option` | `custom_field_updated` | Recreate integration after Business ID changes |
| `add_option_*` / `update_option_*` (Business ID, Access Token) | `hellotext_schedule_connect`, `hellotext_business_id_updated` | Connect the store once both settings are saved, sending the WooCommerce version; remove the previous business's integration first when the Business ID changes. The previous API key keeps working until Hellotext accepts the new one |
| `pre_update_option_hellotext_access_token` | `hellotext_retry_failed_connection` | Retry a failed connection when the settings are saved again, even unchanged; the settings page shows the failure |
| `admin_init` | `hellotext_settings_init` | Register plugin settings |
| `admin_head` / `wp_head` | `hellotext_script` | Inject frontend/admin scripts |
| `wp_enqueue_scripts` | `hellotext_enqueue_script` | Load the latest Hellotext.js and `assets/storefront.js` on the storefront, with its settings in `window.hellotextWoo` |

## WooCommerce Compatibility

Expand All @@ -435,11 +431,11 @@ Do not add a formal HPOS compatibility declaration until the release candidate h

#### `hellotext_create_profile`

Triggers profile creation/association.
Triggers profile creation/association. Fire it only from requests the customer makes, since it links the profile to the browser's Hellotext.js session.

**Parameters:**

- `$payload` - Either user ID (int) or billing data (array)
- `$payload` - User ID (int), billing data (array), or nothing for the current user

**Usage:**

Expand All @@ -460,30 +456,47 @@ do_action('hellotext_create_profile', [

The plugin automatically hooks into these WooCommerce actions:

- `woocommerce_after_order_details` - Track order placement
- `woocommerce_checkout_order_processed` / `woocommerce_store_api_checkout_order_processed` - Capture the checkout session
- `woocommerce_thankyou` - Track order placement
- `woocommerce_order_status_changed` - Track order status updates
- `woocommerce_order_refunded` - Track refunds
- `woocommerce_add_to_cart` - Track cart additions
- `woocommerce_cart_item_removed` - Track cart removals
- `woocommerce_applied_coupon` - Track coupon usage
- `wp_footer` - Inject tracking scripts and webchat
- `template_redirect` - Track the cart page and the checkout
- `wp_enqueue_scripts` - Load Hellotext.js. Webchat, popups and other widgets are configured from Hellotext

## Testing
### Storefront script

For testing information, see [DEVELOPMENT.md](DEVELOPMENT.md).
`assets/storefront.js` starts Hellotext.js with the settings the plugin prints in `window.hellotextWoo`. After `Hellotext.initialize()`, it:

1. Sets `Hellotext.page.section`, so every event of the page reports it, Webchat messages included.
2. Tracks `page.viewed`, which Hellotext.js does not do on its own, except on product pages (`product.viewed`) and the checkout (`checkout.started`).
3. Calls `Hellotext.alert.show(section)`. Hellotext shows the alert only for the sections enabled in the Smart Alert playbook.

## Environment Variables
It also listens for the `cart.added` event that the Webchat's product cards dispatch, and adds the card's product to the WooCommerce cart through `?wc-ajax=add_to_cart`, with the message in `hellotext_source` so the plugin credits the addition to it. It then refreshes the mini cart with `added_to_cart`, as WooCommerce's own buttons do. Products that need options open their page, and the store's "Redirect to the cart page after successful addition" setting is followed.

The plugin respects the following environment variables:
### Page sections

- `APP_ENV` - Environment mode: `production`, `development`, or `test`
- `HELLOTEXT_API_URL` - Override API URL (development only)
| Page | Section |
| ------------------------------------------------- | -------------------- |
| Front page (also when the shop is the front page) | `homepage` |
| Shop, product categories, tags and attributes | `product_collection` |
| Product | `product_details` |
| Anything else (cart, checkout, account, blog) | none |

**Example (.htaccess):**
The Smart Alert subscribes visitors to Push, which needs a service worker on the store's origin. The plugin ships `assets/hellotext-service-worker.js`, the worker from the Hellotext.js Push guide, and passes its path as `push.serviceWorkerUrl`. It registers under the plugin's folder, so it never replaces a worker the store already runs at the site root.

```apache
SetEnv APP_ENV development
SetEnv HELLOTEXT_API_URL https://api-dev.hellotext.com
## Testing

For testing information, see [DEVELOPMENT.md](DEVELOPMENT.md).

## Configuration Constants

Define `HELLOTEXT_API_URL` in `wp-config.php` to point the plugin at another Hellotext environment:

```php
define('HELLOTEXT_API_URL', 'https://api-dev.hellotext.com');
```

## Error Handling
Expand Down
29 changes: 9 additions & 20 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,27 +53,13 @@ This installs:

### 3. Configure Environment

Create or modify your WordPress configuration to set environment variables.

**Option A: wp-config.php**
The plugin talks to `https://api.hellotext.com` by default. To use another Hellotext environment, define `HELLOTEXT_API_URL` in `wp-config.php`:

```php
// Add before "That's all, stop editing!"
$_ENV['APP_ENV'] = 'development';
$_ENV['HELLOTEXT_API_URL'] = 'https://api-dev.hellotext.com';
```

**Option B: .htaccess**

```apache
SetEnv APP_ENV development
SetEnv HELLOTEXT_API_URL https://api-dev.hellotext.com
define('HELLOTEXT_API_URL', 'https://api-dev.hellotext.com');
```

**Option C: Server Configuration**

For Local by Flywheel, add to site configuration or use `.env` file if supported.

### 4. Activate Plugin

1. Navigate to WordPress admin → Plugins
Expand Down Expand Up @@ -352,9 +338,12 @@ add_action('all', function($hook) {
- [ ] Inspect the production `vendor/` tree enough to confirm dev-only packages such as Pest, Mockery, stubs, PHPUnit, and PHP CS Fixer are not included in the release build.
- [ ] Verify `.distignore` excludes development files from the release zip: `.github/`, `tests/`, `composer.json`, `composer.lock`, `DEVELOPMENT.md`, and `API.md`.
- [ ] Smoke test the plugin zip in a clean WordPress/WooCommerce site.
- [ ] Confirm settings save correctly: Business ID, access token, webchat ID, placement, and behavior.
- [ ] Confirm script/webchat injection renders on the storefront when configured.
- [ ] Smoke test tracking for product view, cart add/remove, coupon redemption, checkout/order placement, order status change, refund, user registration, plugin activation, and plugin deactivation.
- [ ] Confirm settings save correctly (Business ID and access token) and the store connects once, with a single Hellotext WooCommerce API key.
- [ ] Confirm the storefront loads `https://cdn.jsdelivr.net/npm/@hellotext/hellotext/dist/hellotext.min.js` and the Webchat configured in Hellotext appears.
- [ ] Confirm `Hellotext.page.section` is `homepage`, `product_collection` and `product_details` on the front, shop/category and product pages, and empty on the cart.
- [ ] With the Smart Alert playbook enabled, confirm its sections show on those pages and that "Allow" subscribes through `assets/hellotext-service-worker.js`.
- [ ] From a Webchat product card, confirm "Add to cart" adds the product, refreshes the mini cart on a classic and a block theme, opens the page of a variable product, and that `cart.added` reaches Hellotext with the message as `source`.
- [ ] Smoke test tracking for page view, product view, cart add/remove, cart view, checkout started (once per cart), coupon redemption, checkout/order placement, order status change, refund, user registration, plugin activation, and plugin deactivation.
- [ ] Smoke test classic template pages and WooCommerce Cart/Checkout blocks separately for product, cart, and checkout coverage.
- [ ] Smoke test order placement, order status, and refund flows with WooCommerce HPOS enabled and disabled.
- [ ] Record WooCommerce API/HPOS compatibility notes in the release description if anything changed.
Expand Down Expand Up @@ -525,7 +514,7 @@ composer require --dev php-stubs/wordpress-stubs php-stubs/woocommerce-stubs

**Issue**: `hello_session` cookie not being created

**Solution**: Check that `session_start()` is called early in plugin load and cookie settings (domain, path) are correct.
**Solution**: Hellotext.js sets the cookie in the browser. Check that the storefront loads Hellotext.js (Business ID saved, no script blocker or Content Security Policy rejecting `cdn.jsdelivr.net`).

### API Requests Failing

Expand Down
Loading
Loading