| 1 |
<?php |
| 2 |
/** |
| 3 |
* Live mode: the daily subscription (entitlement) check. |
| 4 |
* |
| 5 |
* Soft gate semantics (locked 2026-07-03): fail-open on check errors — a |
| 6 |
* network/server problem keeps the last definitive answer and retries hourly; |
| 7 |
* fail-closed only on an explicit "not entitled" (auth-rejected) answer, |
| 8 |
* which also deletes the stored MLS metadata + live config. Re-subscribing |
| 9 |
* re-fetches everything through the normal setup fetch. |
| 10 |
* |
| 11 |
* @package Mlsimport |
| 12 |
*/ |
| 13 |
|
| 14 |
if ( ! defined( 'ABSPATH' ) ) { |
| 15 |
exit; |
| 16 |
} |
| 17 |
|
| 18 |
/** |
| 19 |
* Whether the MLSImport subscription is (still) considered active. |
| 20 |
* |
| 21 |
* @return bool |
| 22 |
*/ |
| 23 |
function mlsimport_live_entitled(): bool { |
| 24 |
// Only hit the SaaS when the per-check throttle transient has lapsed. |
| 25 |
if ( false === get_transient( 'mlsimport_live_entitlement_checked' ) ) { |
| 26 |
mlsimport_live_entitlement_refresh(); |
| 27 |
} |
| 28 |
// Fail-open: anything other than a definitive 'no' counts as entitled. |
| 29 |
return 'no' !== get_option( 'mlsimport_live_entitlement_state', 'yes' ); |
| 30 |
} |
| 31 |
|
| 32 |
/** |
| 33 |
* Run the entitlement check against the SaaS and store the outcome. |
| 34 |
* |
| 35 |
* @return void |
| 36 |
*/ |
| 37 |
function mlsimport_live_entitlement_refresh(): void { |
| 38 |
// A GET /clients that returns the client's mls_data proves the subscription. |
| 39 |
$answer = ThemeImport::globalApiRequestSaas( 'clients', array(), 'GET' ); |
| 40 |
|
| 41 |
// Entitled: record 'yes' and throttle the next check to a day out. |
| 42 |
if ( is_array( $answer ) && ! empty( $answer['mls_data'] ) ) { |
| 43 |
update_option( 'mlsimport_live_entitlement_state', 'yes' ); |
| 44 |
set_transient( 'mlsimport_live_entitlement_checked', 1, DAY_IN_SECONDS ); |
| 45 |
return; |
| 46 |
} |
| 47 |
|
| 48 |
// Only an explicit auth rejection (401/403) is a definitive "not entitled". |
| 49 |
$code = is_array( $answer ) && isset( $answer['error_code'] ) ? (int) $answer['error_code'] : 0; |
| 50 |
if ( in_array( $code, array( 401, 403 ), true ) ) { |
| 51 |
// Definitive "not entitled": close the gate and drop the MLS data the |
| 52 |
// subscription paid for. Setup re-fetches it on re-subscribe. |
| 53 |
update_option( 'mlsimport_live_entitlement_state', 'no' ); |
| 54 |
// Drop the MLS metadata + live config the subscription paid for; setup |
| 55 |
// re-fetches all of it on re-subscribe. |
| 56 |
delete_option( 'mlsimport_mls_metadata_mls_data' ); |
| 57 |
delete_option( 'mlsimport_mls_metadata_mls_enums' ); |
| 58 |
delete_option( 'mlsimport_mls_metadata_populated' ); |
| 59 |
delete_option( 'mlsimport_live_mls_config' ); |
| 60 |
// Throttle a day out like the entitled path. |
| 61 |
set_transient( 'mlsimport_live_entitlement_checked', 1, DAY_IN_SECONDS ); |
| 62 |
return; |
| 63 |
} |
| 64 |
|
| 65 |
// Indeterminate (network error, 5xx, token endpoint down): keep the last |
| 66 |
// definitive state and retry sooner. |
| 67 |
set_transient( 'mlsimport_live_entitlement_checked', 1, HOUR_IN_SECONDS ); |
| 68 |
} |
| 69 |
|
| 70 |
/** |
| 71 |
* Admin notice when the subscription check has closed the gate. |
| 72 |
* |
| 73 |
* @return void |
| 74 |
*/ |
| 75 |
function mlsimport_live_entitlement_notice(): void { |
| 76 |
// Only show admins the pause notice, and only when the gate is actually closed. |
| 77 |
if ( ! current_user_can( 'manage_options' ) || 'no' !== get_option( 'mlsimport_live_entitlement_state', 'yes' ) ) { |
| 78 |
return; |
| 79 |
} |
| 80 |
// Render the dismissible-less error notice explaining why listings stopped. |
| 81 |
echo '<div class="notice notice-error"><p>' |
| 82 |
. esc_html__( 'MLSImport live mode is paused: your subscription appears to be inactive. Listings are no longer served. Renew your subscription and reconnect to resume.', 'mlsimport' ) |
| 83 |
. '</p></div>'; |
| 84 |
} |
| 85 |
|