Skip to main content

EnvironmentResolver

\Benecaster\Staging\EnvironmentResolver

Class Free

The one place BENECASTER_IS_PRODUCTION and BENECASTER_STAGING are read, and the one place the precedence between them is expressed. Ask it what the operator has declared; ask StagingManager::is_staging() or InstallIdentity::is_production() what is actually true.

The precedence, in order. BENECASTER_IS_PRODUCTION wins everywhere — over BENECASTER_STAGING and over hostname detection, so an install with both constants set is production. Failing that, BENECASTER_STAGING means staging. With neither set the answer is Undeclared, and the caller falls through to whatever detection it owns.

Undeclared is not production. It means nobody has said. Collapsing the three cases to a boolean is exactly how the two constants ended up answered in two different classes with nothing reconciling them.

Why production wins. Declaring production only ever removes that install’s own safety rails — it re-enables live Stripe key saves and re-exposes the install to the clone guard’s refusals — and buys nothing from the licence server, which derives its own view of is_staging from the verified hostname and is not obliged to believe a constant. The opposite order would be the unsafe one: a BENECASTER_STAGING left behind in a copied wp-config.php could silently strip a genuine production site of its tier logic with no way to override it.

Reads constants only, so it holds no dependencies and is safe to construct anywhere. It does not cache.

Methods

Method Visibility Since Description
declared(): EnvironmentDeclaration Public What the operator has declared, as a Benecaster\Staging\EnvironmentDeclaration enum case — Production, Staging or Undeclared. This is the method to reach for when your add-on wants to branch three ways rather than two.
production_declared(): bool Public True when BENECASTER_IS_PRODUCTION is set and truthy. ⚠ Not the same question as "is this install production?" — an install with neither constant set answers false here and may still be perfectly ordinary production. For that question, ask InstallIdentity::is_production().
staging_declared(): bool Public True when BENECASTER_STAGING is set and truthy and BENECASTER_IS_PRODUCTION is not. That second half is the precedence, and it is why this is not a bare defined( 'BENECASTER_STAGING' ).

Notes

## A constant defined to false counts as not set

The check is on the constant's value, not on defined(). Someone writing define( 'BENECASTER_STAGING', false ); to turn staging off means it, and a defined() test alone would have read that as switching it on. false, '0' and '' all read as not set.

## Do not read either constant directly

Reading BENECASTER_STAGING yourself gets the answer wrong on an install that also declares production, and reading BENECASTER_IS_PRODUCTION yourself gets it wrong by treating an undeclared install as staging. Both mistakes shipped: until 2026-09-04 the two constants were answered inside StagingManager::is_staging() and InstallIdentity::production_override_active() with nothing reconciling them, so setting both produced an install that was staging by one answer and production by the other — orange admin bar and a capped subscriber count on every /validate ping, while live Stripe keys saved without complaint. That is the combination the key guard exists to prevent, reached by setting two documented constants.

## Both constant names are permanent

BENECASTER_IS_PRODUCTION is not "the inverse of BENECASTER_STAGING" and is not redundant. Its primary job is overriding InstallIdentity::is_non_production_copy(), which compares the install's recorded canonical URL against its current one and is hostname-blind by design — no staging constant reaches it, and a production site that has legitimately changed domain has no other route back to its own commerce.