AvailabilityRepository
\Benecaster\Availability\AvailabilityRepository
Data access for the benecaster_availability table, which holds one row per episode and tier saying when that tier’s feed gets the episode. It also owns the conversion between the two time representations availability uses, and every query in it goes through $wpdb->prepare().
Stored availability datetimes are UTC. The values callers pass in, and the values a podcaster types into the episode editor, are site-local. upsert() converts on the way in, so every write passes through one point whichever caller made it. Reads return UTC, so anything that shows a stored datetime to a person must convert it back with to_local(). A UTC value handed to the editor’s timezone-naive datetime-local input displays as the wrong hour with nothing to show why. Times are stored as absolute UTC because a naive local time is ambiguous twice a year: one wall-clock hour happens twice on the fall-back night and another does not exist on the spring-forward night.
An add-on that sells episode access uses upsert() to put episodes behind its grant slug. Availability rows for a grant slug are written exactly as they are for a tier; see Grant a listener access to an episode or a bundle from an add-on. The class has no hooks of its own; the benecaster_availability_set, benecaster_availability_unlocked and benecaster_availability_check_run actions and the benecaster_availability_datetimes filter are fired by other availability classes. To ask whether a user can hear an episode right now, use benecaster_user_can_access_episode().
Methods
| Method | Visibility | Since | Description |
|---|---|---|---|
static to_utc( string $local_datetime ): string |
Public | — | Converts a site-local Y-m-d H:i:s datetime to UTC. Resolves against the site's timezone (Settings → General), the timezone the podcaster typed the value in, not PHP's process timezone, which WordPress does not guarantee matches it. Empty or whitespace-only input is returned trimmed and unchanged rather than becoming an epoch date. |
static to_local( string $utc_datetime ): string |
Public | — | Converts a stored UTC Y-m-d H:i:s datetime back to the site's timezone for display. Empty or whitespace-only input is returned trimmed and unchanged. |
upsert( int $episode_id, int $show_id, string $tier_slug, string $available_datetime ): bool |
Public | — | Inserts the availability row for an episode and tier, or updates it when one exists (the table has a unique key on episode and tier). $available_datetime must be site-local; it is converted to UTC here, so passing a UTC value converts it a second time and stores it wrong by the site's offset. The update changes the show ID and the datetime. Returns false when the query fails. This is the one place every write passes through, including the buy-up availability sync, which calls it directly and skips the availability manager. |
delete_for_episode( int $episode_id ): int |
Public | — | Deletes every tier's availability row for an episode and returns the number of rows deleted. Used when an episode is permanently deleted. |
delete_for_episode_and_tier( int $episode_id, string $tier_slug ): bool |
Public | — | Deletes the one row for an episode and tier, for example when a podcaster removes a tier from an episode's schedule. Returns false when the query fails, and true when it succeeds even if no row matched. |
find_by_episode( int $episode_id ): array |
Public | — | Returns every availability row for an episode as objects with all columns, ordered by tier slug. The episode editor uses it to draw the availability timeline. available_datetime is UTC. |
find_by_episode_and_tier( int $episode_id, string $tier_slug ): ?object |
Public | — | Returns the single row for an episode and tier, or null when there is none. available_datetime is UTC. |
find_available_episode_ids( int $show_id, string $tier_slug, int $limit = 300 ): array |
Public | — | Returns the IDs of episodes whose availability datetime for that show and tier is at or before the current UTC time, newest first. This is the read path feed compilation uses, backed by a composite index on show, tier and datetime. The default limit is 300; a limit of 0 or less removes it. The comparison uses UTC_TIMESTAMP(), so it does not depend on the database server's timezone. |
find_upcoming_change_datetime( int $show_id, string $tier_slug ): ?string |
Public | — | Returns the earliest availability datetime after the current UTC time for the show and tier, as a UTC string, or null when nothing is scheduled. Nothing in the plugin calls it; the feed cache uses a fixed expiry and does not consult it. |
find_recently_passed( string $since_datetime ): array |
Public | — | Returns rows whose availability datetime is after $since_datetime and at or before the current UTC time, as objects with episode_id, show_id, tier_slug and available_datetime. The scheduled availability check uses it to find episodes that just unlocked so it can invalidate the affected tier feeds. $since_datetime must be UTC. |
Notes
Use UTC_TIMESTAMP() and never NOW() in any query against this table. NOW() resolves against the MySQL session timezone, which WordPress never sets, and on hosting where the database runs in UTC while PHP uses the site's timezone it disagrees with PHP's own clock at the same instant.