| @@ -232,8 +232,27 @@ | ||
| 232 | 232 | | `license_check_deferred` | A scheduled check couldn't reach the server but the license is still honoured (within grace). | `$license` | |
| 233 | 233 | | `update_installed` | This product's files were updated in place (native "Update now"/bulk/auto-update, or the SDK installer). | `$previous_version` | |
| 234 | 234 | | `update_failed` | An SDK-driven install failed. | `$wp_error, $target_version, $current_version` | |
| 235 | 235 | |
| 236 | +### Updates and license state | |
| 237 | + | |
| 238 | +Updates for a pro product are gated on the license. The license server omits the | |
| 239 | +download URL for an unlicensed site, and WordPress renders "Automatic update is | |
| 240 | +unavailable for this plugin" whenever an update row has no `package`. Because the | |
| 241 | +server response is cached locally, the SDK also: | |
| 242 | + | |
| 243 | +- drops the cached version info on every license lifecycle transition | |
| 244 | + (`license_activated`, `license_deactivated`, `license_grace_expired`), so a | |
| 245 | + download URL obtained under an active license cannot outlive it — this covers | |
| 246 | + the PHP license form, the REST endpoints, WP-CLI and the scheduled re-check | |
| 247 | + alike; and | |
| 248 | +- blanks `package` / `download_link` for a pro product with no valid license as | |
| 249 | + the update payload is injected, as a backstop for any payload cached before | |
| 250 | + this behaviour existed. | |
| 251 | + | |
| 252 | +Free products are never gated, and a license inside its **offline grace period** | |
| 253 | +still counts as valid — a server outage does not strip working updates. | |
| 254 | + | |
| 236 | 255 | ### Offline grace period |
| 237 | 256 | |
| 238 | 257 | If the license server can't be reached during the daily re-check (DNS/timeout/TLS |
| 239 | 258 | failure, a blocked outbound request, or a 5xx), a previously-valid license keeps |
| @@ -240,8 +259,48 @@ | ||
| 240 | 259 | working for a grace window (default **14 days** since the last successful |
| 241 | 260 | verification) instead of being deactivated by a transient outage. Configure it |
| 242 | 261 | with the `license_grace_period` init arg (seconds; `0` = fail closed |
| 243 | 262 | immediately) or the `{hook}_license_grace_period` filter. |
| 263 | + | |
| 264 | +## Talking to the license server | |
| 265 | + | |
| 266 | +The SDK is built so a slow or failing license server can never slow down a customer's site, and so the server can steer every 1.6.0+ install without a new SDK release. | |
| 267 | + | |
| 268 | +- **No requests during page loads.** Update data, promotions and the localized JS params read cached data only. When something is due, one cron event is scheduled. | |
| 269 | +- **One request per site.** That event, and WordPress's own update cron, send a single `check-updates` request for every SDK product on the site that shares a license server. Servers without that route get one `check-update` per product. | |
| 270 | +- **Circuit breaker, shared by every product.** After a timeout, DNS/TLS error, 5xx, 408 or 429, background requests stop for 15 min → 30 min → … → 6 h (±25 %), or as long as `Retry-After` says. Explicit user actions (activate, deactivate, "check now", install) still go out, with a 30-second timeout. | |
| 271 | +- **Randomised timing.** Cache lifetimes, back-offs and the first daily license check are spread, so sites that failed or updated together don't come back together. | |
| 272 | + | |
| 273 | +### Server directives | |
| 274 | + | |
| 275 | +Any `check-update` response, a `check-updates` item, or the top level of a `check-updates` response may include: | |
| 276 | + | |
| 277 | +| Field | Effect | | |
| 278 | +|---|---| | |
| 279 | +| `next_check_in` (seconds) | How long this answer is cached. Clamped to 1 hour – 7 days. A top-level value applies to items that don't set their own. | | |
| 280 | +| `pause_background` (seconds) | Stop all background requests to this server for that long (max 7 days; never shorter than asked). `0` lifts a pause. User actions are unaffected and don't lift it. | | |
| 281 | + | |
| 282 | +### Filters | |
| 283 | + | |
| 284 | +| Filter | Default | | |
| 285 | +|---|---| | |
| 286 | +| `{hook}_updater_cache_ttl` | 12 h | | |
| 287 | +| `{hook}_updater_failure_ttl` | 1 h | | |
| 288 | +| `{hook}_versions_cache_ttl` | 6 h | | |
| 289 | +| `se_license_sdk_server_backoff` | 15 min × 2ⁿ, max 6 h | | |
| 290 | +| `se_license_sdk_interactive_timeout` | 30 s (15–30) | | |
| 291 | +| `se_license_sdk_can_fetch_inline` | true in cron, WP-CLI and Dashboard → Updates "Check again" | | |
| 292 | + | |
| 293 | +## Development | |
| 294 | + | |
| 295 | +`tests/run.sh` runs end-to-end scenarios against a WordPress install with a faked license server (nothing leaves the machine): | |
| 296 | + | |
| 297 | +```bash | |
| 298 | +WP_PATH=/path/to/wordpress tests/run.sh # all scenarios | |
| 299 | +WP_PATH=/path/to/wordpress tests/run.sh signature # filter by name | |
| 300 | +``` | |
| 301 | + | |
| 302 | +CI runs them on PHP 7.4 and 8.3 for every pull request, together with `tests/check-version.sh`, which fails a PR that changes SDK code without bumping the version in `init.php` (unbumped code is silently ignored wherever another plugin bundles the same version) or without a changelog entry. | |
| 244 | 303 | |
| 245 | 304 | ## Learn More |
| 246 | 305 | |
| 247 | 306 | Visit our official website [storeengine.pro](https://storeengine.pro) for more details on selling WordPress plugins and themes online. |