| @@ -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 |