# LiquidWeb Harbor

[![PHP Compatibility](https://github.com/stellarwp/harbor/actions/workflows/compatibility.yml/badge.svg)](https://github.com/stellarwp/harbor/actions/workflows/compatibility.yml)
[![PHP Tests](https://github.com/stellarwp/harbor/actions/workflows/tests-php.yml/badge.svg)](https://github.com/stellarwp/harbor/actions/workflows/tests-php.yml)
[![PHPStan](https://github.com/stellarwp/harbor/actions/workflows/static-analysis.yml/badge.svg)](https://github.com/stellarwp/harbor/actions/workflows/static-analysis.yml)
[![E2E Tests](https://github.com/stellarwp/harbor/actions/workflows/tests-e2e.yml/badge.svg)](https://github.com/stellarwp/harbor/actions/workflows/tests-e2e.yml)

## Installation

It's recommended that you install Harbor as a project dependency via [Composer](https://getcomposer.org/):

```bash
composer require stellarwp/harbor
```

> We _actually_ recommend that this library gets included in your project using [Strauss](https://github.com/BrianHenryIE/strauss).
>
> Luckily, adding Strauss to your `composer.json` is only slightly more complicated than adding a typical dependency, so checkout our [strauss docs](https://github.com/stellarwp/global-docs/blob/main/docs/strauss-setup.md).

## Initialize the library

Initializing the Harbor library should be done within the `plugins_loaded` action, preferably at priority `0`.

```php
use LiquidWeb\Harbor\Config;
use LiquidWeb\Harbor\Harbor;

add_action( 'plugins_loaded', function() {
 /**
  * Configure the container.
  *
  * The container must be compatible with stellarwp/container-contract.
  * See here: https://github.com/stellarwp/container-contract#usage.
  *
  * If you do not have a container, we recommend https://github.com/lucatume/di52
  * and the corresponding wrapper:
  * https://github.com/stellarwp/container-contract/blob/main/examples/di52/Container.php
  */
 $container = new Container();
 // Use a plugin basename constant defined in your main plugin file,
 // e.g. define( 'MY_PLUGIN_BASENAME', plugin_basename( __FILE__ ) )
 Config::set_plugin_basename( MY_PLUGIN_BASENAME );
 Config::set_container( $container );
 Harbor::init();
}, 0 );
```

## Translation

Package is using `__( 'Invalid request: nonce field is expired. Please try again.', '%TEXTDOMAIN%' )` function for translation. In order to change domain placeholder `'%TEXTDOMAIN%'` to your plugin translation domain run

```bash
./bin/stellar-harbor domain=<your-plugin-domain>
```

or

```bash
./bin/stellar-harbor
```

and prompt the plugin domain
You can also add lines below to your composer file in order to run command automatically

```json
"scripts": {
 "stellar-harbor": [
   "vendor/bin/stellar-harbor domain=<your-plugin-domain>"
 ],
 "post-install-cmd": [
   "@stellar-harbor"
 ],
 "post-update-cmd": [
   "@stellar-harbor"
 ]
  }
```

## Registering a plugin

Harbor discovers your plugin's embedded key automatically by scanning active plugins for a file named `LWSW_KEY.php` in the plugin root. No filter registration is required. See the [Harbor Integration Guide](/docs/guides/integration.md) for more details.

## Changelog

This project uses [@stellarwp/changelogger](https://github.com/stellarwp/changelogger) to manage its changelog. All notable changes are tracked via changelog entry files in the `changelog/` directory.

To add a new changelog entry:

```bash
bunx @stellarwp/changelogger add
```

To compile changelog entries into `changelog.txt`:

```bash
bunx @stellarwp/changelogger write --overwrite-version <version>
```

## Releasing

1. Run the **Release Prep** workflow (`Actions → Release Prep → Run workflow`). Supply the target branch, version (e.g. `1.2.0`), and the release date (e.g. `2026-04-29`). The workflow bumps the `VERSION` constant, compiles the changelog, and opens a PR automatically.
2. Review and merge the PR.
3. Create a GitHub Release with a new tag in the format `vX.X.X` targeting the merge commit.

## Documentation

Start with [Harbor Overview](/docs/harbor.md) for the full architecture.

### Subsystems

- [Licensing](/docs/subsystems/licensing.md) — Key discovery, API responses, validation workflows, caching.
- [Catalog](/docs/subsystems/catalog.md) — Product families, tiers, features, the Commerce Portal API.
- [Features](/docs/subsystems/features.md) — Feature types, resolution, strategies, Manager API.
- [Cron](/docs/subsystems/cron.md) — Scheduled refresh of catalog and licensing data.
- [Frontend](/docs/subsystems/frontend.md) — React app, @wordpress/data store, component hierarchy, CSS scoping.
- [Notices](/docs/subsystems/notices.md) — Admin notices, legacy license warnings, persistent dismissal.

### Architecture

- [Unified License Key](/docs/architecture/unified-license-key-system-design.md) — Key model, seat mechanics, system boundaries.
- [Fat Leader / Thin Instance](/docs/architecture/fat-leader-thin-instance.md) — Leader election, cross-instance hooks.
- [Conventions](/docs/architecture/conventions.md) — Naming conventions for namespaces, packages, identifiers.

### API Reference

- [REST: License](/docs/api/rest/license.md) — License endpoints.
- [REST: Catalog](/docs/api/rest/catalog.md) — Catalog endpoints.
- [REST: Features](/docs/api/rest/features.md) — Feature endpoints.
- [REST: Legacy Licenses](/docs/api/rest/legacy-licenses.md) — Legacy license endpoints.
- [Liquid Web Licensing v1](/docs/api/liquid-web-software-licensing-v1.md) — External licensing API consumed by Harbor.

### Guides

- [Integration Guide](/docs/guides/integration.md) — How to integrate your plugin with Harbor.
- [CLI Commands](/docs/guides/cli.md) — WP-CLI commands for feature management.
- [Testing](/docs/guides/testing.md) — PHP tests with Codeception/`slic`; E2E tests with Playwright/wp-env.
