# Snooze Public API

This document is the reference for the Snooze feature's public PHP API,
intended for theme overrides and external WooCommerce plugins.

- **Source:** [`src/api/snooze.php`](../src/api/snooze.php)
- **Available since:** 2.13.0
- **Stability:** Signatures, return types and side-effects are stable
  across minor releases. Breaking changes follow a normal deprecation
  cycle (one minor with `@deprecated` plus a `_doing_it_wrong()`-style
  notice before removal).

The procedural functions below are the supported entry point for code
that lives outside the plugin's `app/` directory. Plugin-internal code
should resolve the relevant service interface from the container instead.

## Settings

### `autoship_is_snooze_enabled(): bool`
Whether the merchant has enabled the Snooze feature in plugin settings.

### `autoship_get_snooze_action_label(): string`
Merchant-configured display label for the Snooze action (e.g.
`"Snooze"`, `"Pause"`, `"Pause my order"`). Use this rather than
hard-coding strings in UI overrides.

### `autoship_get_snooze_pause_behavior(): string`
Returns either `"alongside"` (Snooze appears next to the standard
Pause action) or `"instead"` (Snooze replaces Pause).

### `autoship_get_snooze_frequency_source(): string`
Returns either `"qmc"` (frequencies come from QPilot's
CustomerPortalSettings) or `"plugin"` (the merchant's locally
configured defaults are used).

### `autoship_is_snooze_custom_date_allowed(): bool`
Whether subscribers may pick an arbitrary calendar date as their
resume date, in addition to the preset frequencies.

### `autoship_get_snooze_max_duration_days(): int`
Merchant-configured cap on snooze duration, in days. `0` means no cap.

## Order Status Helpers

### `autoship_is_order_snoozed(object|array $order): bool`
Whether a scheduled order is in the composite snoozed state.

Snooze is **not** a distinct backend status — it is the composite of
`status === "Paused"` AND a populated `snoozeUntilUtc` AND
`snoozeDuration > 0`. Templates and integrations should use this helper
rather than checking the status string directly.

### `autoship_format_snooze_duration_label(int $duration, string $duration_type): string`
Format a duration as a human-readable label. Examples:

| Input              | Output       |
| ------------------ | ------------ |
| `(1, 'Weeks')`     | `"1 Week"`   |
| `(2, 'Weeks')`     | `"2 Weeks"`  |
| `(3, 'Months')`    | `"3 Months"` |

Result passes through the
[`autoship_snooze_duration_label`](#related-filter-hooks) filter.

### `autoship_calculate_snooze_resume_date(int $duration, string $duration_type): string`
Returns the UTC ISO 8601 resume date for a snooze of the given length.
Days/Weeks/Months advance from "now" in the UTC timezone. Format:
`Y-m-d\TH:i:s\Z`.

### `autoship_get_snooze_until_text(object|array $autoship_order): string`
Localised "Snoozed until [date]" text. Returns `''` when the order is
not snoozed, so it is safe to echo unconditionally.

### `autoship_get_snooze_resume_date_formatted(object|array $autoship_order): string`
Localised resume date for a snoozed order, **without** any surrounding
text. Use this when you want to compose your own sentence around the
date (e.g. "Auto-resumes on …", "Will resume …") rather than the fixed
"Snoozed until …" message produced by
`autoship_get_snooze_until_text()`.

Format is `get_option( 'date_format' )` applied via `date_i18n()`. Both
this helper and `autoship_get_snooze_until_text()` share the same
underlying date-formatting code, so the two messages stay in lockstep.

Returns `''` when the order is not snoozed or the `snoozeUntilUtc`
value is unparseable.

## Duration Options

### `autoship_get_default_snooze_options(): array`
Plugin-default frequency list. Used when the merchant has selected
`"plugin"` as the frequency source, or as a fallback when QMC returns
nothing usable.

### `autoship_get_snooze_options(bool $refresh = false): array`
Resolved snooze frequency list for the current site. Routes through
the configured source (QMC or plugin), applies the transient cache,
and falls back to plugin defaults when QMC returns nothing.

Pass `$refresh = true` to bypass the cache. Result passes through the
[`autoship_snooze_frequencies`](#related-filter-hooks) filter.

Each entry is an associative array with the following keys:

| Key            | Type   | Description                                |
| -------------- | ------ | ------------------------------------------ |
| `Duration`     | int    | The duration value.                        |
| `DurationType` | string | One of `Days`, `Weeks`, `Months`.          |
| `IsDefault`    | bool   | Whether this option is the default choice. |
| `Enabled`      | bool   | Whether this option is currently active.   |
| `Order`        | int    | Display order, ascending.                  |

### `autoship_clear_snooze_options_cache(): void`
Invalidate the cached QMC snooze frequencies for the current site.
Call after writing settings that affect the QMC payload.

## QPilot Feature Flags

### `autoship_get_site_feature_flags(): array`
The merged global + site feature flag list returned by QPilot, as an
indexed array of flag name strings.

### `autoship_is_qpilot_snooze_flag_enabled(): bool`
Whether the QPilot `enable-snooze` flag is enabled.

**Permissive default:** returns `true` when the flag list cannot be
fetched (transient outage, no credentials), so an outage does not
silently disable Snooze for already-onboarded sites.

### `autoship_qpilot_snooze_flag_definitively_off(): bool`
Whether QPilot definitively reports the `enable-snooze` flag as off.
Distinguishes "fetch failed" from "fetch succeeded and flag is absent"
— used by the admin warning banner so we only nag merchants when we
are sure the flag is off.

## Related Filter Hooks

The procedural API is complemented by the following filters. Both
sides of the public surface are stable from 2.13.0 onwards.

### `autoship_snooze_frequencies`
Filters the resolved snooze frequency list returned by
`autoship_get_snooze_options()`.

```php
add_filter( 'autoship_snooze_frequencies', function ( array $options ) {
    // Add a "1 Year" option.
    $options[] = array(
        'Duration'     => 12,
        'DurationType' => 'Months',
        'IsDefault'    => false,
        'Enabled'      => true,
        'Order'        => 99,
    );

    return $options;
} );
```

### `autoship_snooze_duration_label`
Filters the human-readable duration label returned by
`autoship_format_snooze_duration_label()`. Receives the formatted
label, the duration value, and the duration type.

### `autoship_snooze_frequency_source`
Filters the configured frequency source (`qmc` or `plugin`) before it
is returned by `autoship_get_snooze_frequency_source()`.

### `autoship_snooze_frequencies_cache_ttl`
Filters the cache TTL (in seconds) used when storing the resolved QMC
frequency list. Default is `3600`.

## Container Fallback Semantics

Every settings/options function in `src/api/snooze.php` guards against
`Plugin::get_service_container()` returning `null`. That branch is only
reachable during very early bootstrap (before `plugins_loaded`) or
during uninstall, when the DI container has not been built.

The fallback values are picked to be safe defaults:

| Function                                       | Fallback     |
| ---------------------------------------------- | ------------ |
| `autoship_is_snooze_enabled()`                 | `false`      |
| `autoship_get_snooze_action_label()`           | `"Snooze"`   |
| `autoship_get_snooze_pause_behavior()`         | `"alongside"` |
| `autoship_get_snooze_frequency_source()`       | `"qmc"`      |
| `autoship_is_snooze_custom_date_allowed()`     | `false`      |
| `autoship_get_snooze_max_duration_days()`      | `0`          |
| `autoship_get_snooze_until_text()`             | `""`         |
| `autoship_get_snooze_resume_date_formatted()`  | `""`         |
| `autoship_get_default_snooze_options()`        | `[]`         |
| `autoship_get_snooze_options()`                | `[]`         |
| `autoship_clear_snooze_options_cache()`        | no-op        |
| `autoship_get_site_feature_flags()`            | `[]`         |
| `autoship_is_qpilot_snooze_flag_enabled()`     | `true`       |
| `autoship_qpilot_snooze_flag_definitively_off()` | `false`    |

If you observe a fallback value during a normal page load, that
indicates a bootstrap-ordering bug — the public API is not designed
to mask runtime configuration errors.

## Internal Service Equivalents

For plugin-internal code (anything under `app/`), inject the
underlying service rather than calling the procedural function.

| Public API                                     | Internal equivalent                                                  |
| ---------------------------------------------- | -------------------------------------------------------------------- |
| `autoship_is_snooze_enabled()`                 | `SnoozeSettingsInterface::is_enabled()`                              |
| `autoship_get_snooze_action_label()`           | `SnoozeSettingsInterface::get_action_label()`                        |
| `autoship_get_snooze_pause_behavior()`         | `SnoozeSettingsInterface::get_pause_behavior()`                      |
| `autoship_get_snooze_frequency_source()`       | `SnoozeSettingsInterface::get_frequency_source()`                    |
| `autoship_is_snooze_custom_date_allowed()`     | `SnoozeSettingsInterface::is_custom_date_allowed()`                  |
| `autoship_get_snooze_max_duration_days()`      | `SnoozeSettingsInterface::get_max_duration_days()`                   |
| `autoship_is_order_snoozed()`                  | `SnoozeStatus::is_snoozed()`                                         |
| `autoship_format_snooze_duration_label()`      | `SnoozeStatus::format_duration_label()`                              |
| `autoship_calculate_snooze_resume_date()`      | `SnoozeStatus::calculate_resume_date()`                              |
| `autoship_get_snooze_until_text()`             | `SnoozeActionFilters::get_snooze_until_text()`                       |
| `autoship_get_snooze_resume_date_formatted()`  | `SnoozeActionFilters::get_snooze_resume_date_formatted()`            |
| `autoship_get_default_snooze_options()`        | `SnoozeOptionsProviderInterface::get_default_options()`              |
| `autoship_get_snooze_options()`                | `SnoozeOptionsProviderInterface::get_options()`                      |
| `autoship_clear_snooze_options_cache()`        | `SnoozeOptionsProviderInterface::clear_cache()`                      |
| `autoship_get_site_feature_flags()`            | `SnoozeFeatureFlagsInterface::get_flags()`                           |
| `autoship_is_qpilot_snooze_flag_enabled()`     | `SnoozeFeatureFlagsInterface::is_snooze_flag_enabled()`              |
| `autoship_qpilot_snooze_flag_definitively_off()` | `SnoozeFeatureFlagsInterface::is_snooze_flag_definitively_off()`   |
