Policy Hierarchy
The Policy Engine resolves every policy value through a 5-level hierarchy. This page explains how the hierarchy works, when each level is appropriate, and how conflicts are resolved.
The 5 levels
Global --> Entitlement Class --> Organization --> Product --> Individual Entitlement| Level | Where it is configured | Typical use case |
|---|---|---|
| Global | Plugin settings in WP Admin | Company-wide defaults for all entitlements |
| Entitlement Class | Per-class settings (PLG, ENV, SVC, ORD, AFL, EDU) | Rules that differ by type of product/service |
| Organization | Organization metadata in WP Admin | Customer-specific exceptions |
| Product | Product YAML policies: block | Rules tied to a specific WooCommerce product |
| Individual Entitlement | Entitlement metadata in WP Admin | One-off exceptions for a single entitlement record |
How override works: most specific wins
The engine resolves each policy field independently by walking from the most specific level up to the least specific:
- Check the individual entitlement -- if a value is set, use it.
- If not set, check the product -- if a value is set, use it.
- If not set, check the organization -- if a value is set, use it.
- If not set, check the entitlement class -- if a value is set, use it.
- If not set, check the global setting -- if a value is set, use it.
- If nothing is set anywhere, use the hardcoded default from the policy schema.
Key rule: no merging
Values are never merged across levels. The winning level provides the entire value for that field. If the global setting defines expiry_warning_days: [30, 7, 1] and an organization overrides it to [60, 30], the organization gets [60, 30] -- not [60, 30, 7, 1]. The override replaces; it does not combine.
Examples
Example 1: Grace period override
Scenario: The global Payment Recovery Policy sets suspended_to_cancelled_days: 30. Organization "Acme Corp" needs 60 days because they have slow internal procurement.
Global: suspended_to_cancelled_days = 30
Class PLG: suspended_to_cancelled_days = 14
Organization Acme: suspended_to_cancelled_days = 60
Product: (not set -- inherits from organization)
Entitlement PLG-001: (not set -- inherits from organization)Result for PLG-001 (owned by Acme): 60 days. The organization override (60) is more specific than the class override (14).
Result for PLG-002 (owned by Beta Corp, no org override): 14 days. Beta Corp has no override, so the class value (14) applies.
Result for SVC-003 (owned by Beta Corp): 30 days. No org override, no class override for SVC on this field, so the global value (30) applies.
Example 2: Credit expiration for an enterprise deal
Scenario: Credits expire in 12 months globally. An enterprise organization negotiated 24-month expiration.
Global: expiration_months = 12
Class SVC: expiration_months = 12 (explicit, same as global)
Organization X: expiration_months = 24
Product SVC-HOST: (not set)
Entitlement SVC-001: (not set)Result for SVC-001 (owned by Org X): 24 months. The organization override wins.
Example 3: Tier change cooldown for a specific product
Scenario: Globally there is no cooldown. The SVC class sets 30 days. A specific hosting product needs 60 days. An enterprise contract negotiated 90 days on one particular entitlement.
Global: cooldown_days = 0
Class SVC: cooldown_days = 30
Organization Z: (not set)
Product SVC-HOST: cooldown_days = 60
Entitlement SVC-005: cooldown_days = 90Result for SVC-005: 90 days. The entitlement-level value is the most specific.
Result for SVC-006 (same product, different entitlement, no entitlement override): 60 days. Falls through to the product level.
Result for SVC-007 (different SVC product, no product or entitlement override): 30 days. Falls through to the class level.
When to use each level
Global
Use for company-wide defaults that apply to all entitlement types. This is where you set your baseline -- the rules that apply unless something more specific overrides them.
Good for: Renewal grace period, notification channels, refund window, data retention period.
Entitlement Class
Use when a category of products needs different rules. Plugins are self-serve and low-touch. Services are high-touch with manual provisioning. Environments need deprovisioning on cancel. These differences are structural, not customer-specific.
Good for: SLA tiers, provisioning mode (auto vs manual), trial availability, refund generosity.
Organization
Use for customer-specific exceptions. An enterprise customer with a negotiated contract might get longer grace periods, extended credit expiration, or a higher SLA tier. A customer with a history of late payments might get stricter payment recovery.
Good for: Negotiated terms, customer-specific SLA, payment recovery adjustments, credit expiration extensions.
Product
Use when a specific WooCommerce product has different rules from others in the same class. A premium hosting plan might have a higher uptime target than the basic plan, even though both are ENV class.
Good for: Product-specific SLA targets, cooldown periods, trial duration, refund terms.
Individual Entitlement
Use sparingly, for one-off exceptions. A specific entitlement that was part of a special deal, a migration edge case, or a customer escalation resolution.
Good for: Contractual exceptions, migration accommodations, escalation resolutions. Should be rare.
Visualizing the cascade
In this diagram, three entitlements resolve the same field (suspended_to_cancelled_days) to three different values based on where overrides are set.
Common mistakes
Setting everything at the entitlement level. If you find yourself overriding the same value on dozens of individual entitlements, you probably need a class-level or organization-level override instead.
Forgetting that overrides replace, not merge. If you set notification.events at the organization level, you must include ALL events you want -- not just the additions. The global list is fully replaced.
Overriding at the wrong level. Customer-specific terms belong at the organization level, not the product level. Product-level overrides affect ALL organizations that buy that product.
Next steps
- Available Policies -- what each policy controls and its fields
- Configuring Policies -- where to set values at each level
- Policy Recipes -- practical step-by-step examples