PluginProbe
Booking Calendar / 11.9
Booking Calendar v11.9
11.9 11.8.4 11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 All 205 releases
booking / includes / _functions / class-wpbc-environment-policy.php

class-wpbc-environment-policy.php in Booking Calendar 11.9, at includes/_functions/class-wpbc-environment-policy.php

335 lines 10.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Shared environment identity and capability policy.
4 *
5 * @package Booking Calendar
6 * @since 11.9.0
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * Provide one authoritative classification for Booking Calendar environments.
15 *
16 * Environment identity is intentionally separate from individual capabilities.
17 * A public live demo may block WordPress page publishing and automatic
18 * onboarding while still allowing selected Setup Wizard configuration. Internal
19 * test sites, including the Free test site, retain normal publishing behavior.
20 */
21 final class WPBC_Environment_Policy {
22
23 /** Standard customer or development installation. */
24 const TYPE_STANDARD = 'standard';
25
26 /** Public, shared Booking Calendar live demo. */
27 const TYPE_PUBLIC_LIVE_DEMO = 'public_live_demo';
28
29 /** Internal Booking Calendar test environment. */
30 const TYPE_INTERNAL_TEST = 'internal_test';
31
32 /** WordPress Playground installation. */
33 const TYPE_PLAYGROUND = 'playground';
34
35 /**
36 * Return the current environment type.
37 *
38 * WordPress's configured home host is authoritative. The current HTTP Host is
39 * used only when no configured host is available, which prevents a request
40 * header from overriding a valid site identity.
41 *
42 * @return string One of the TYPE_* constants.
43 */
44 public static function get_environment_type() {
45 $site_host = self::get_site_host();
46 $request_host = self::get_request_host();
47 $canonical_host = '' !== $site_host ? $site_host : $request_host;
48
49 // A managed public host retains write restrictions even if Playground is also detected.
50 if ( self::is_public_live_demo_host( $canonical_host ) ) {
51 $environment_type = self::TYPE_PUBLIC_LIVE_DEMO;
52 } elseif ( self::is_playground() ) {
53 $environment_type = self::TYPE_PLAYGROUND;
54 } elseif ( self::is_internal_test_host( $canonical_host ) ) {
55 $environment_type = self::TYPE_INTERNAL_TEST;
56 } else {
57 $environment_type = self::TYPE_STANDARD;
58 }
59
60 /**
61 * Filter the authoritative Booking Calendar environment type.
62 *
63 * The returned value must be one of the documented TYPE_* constants. An
64 * unsupported value is ignored so a malformed integration cannot weaken a
65 * detected live-demo restriction.
66 *
67 * @since 11.9.0
68 *
69 * @param string $environment_type Detected environment type.
70 * @param string $canonical_host Normalized host used for classification.
71 * @param string $site_host Normalized WordPress home URL host.
72 * @param string $request_host Normalized request host used as fallback.
73 */
74 $filtered_type = function_exists( 'apply_filters' )
75 ? apply_filters( 'wpbc_environment_type', $environment_type, $canonical_host, $site_host, $request_host )
76 : $environment_type;
77 $allowed_types = array(
78 self::TYPE_STANDARD,
79 self::TYPE_PUBLIC_LIVE_DEMO,
80 self::TYPE_INTERNAL_TEST,
81 self::TYPE_PLAYGROUND,
82 );
83
84 return in_array( $filtered_type, $allowed_types, true ) ? $filtered_type : $environment_type;
85 }
86
87 /**
88 * Determine whether this is a public Booking Calendar live demo.
89 *
90 * @return bool True for a public shared live demo.
91 */
92 public static function is_live_demo() {
93 return self::TYPE_PUBLIC_LIVE_DEMO === self::get_environment_type();
94 }
95
96 /**
97 * Determine whether this is an internal Booking Calendar test environment.
98 *
99 * @return bool True for an explicitly identified internal test host.
100 */
101 public static function is_internal_test() {
102 return self::TYPE_INTERNAL_TEST === self::get_environment_type();
103 }
104
105 /**
106 * Determine whether WordPress is running in Playground.
107 *
108 * @return bool True only for the canonical strict boolean constant.
109 */
110 public static function is_playground() {
111 return defined( 'WPBC_IS_PLAYGROUND' ) && true === WPBC_IS_PLAYGROUND;
112 }
113
114 /**
115 * Determine whether WordPress page discovery and publishing are restricted.
116 *
117 * The released publishing filter is applied here, rather than in an
118 * individual publisher, so every Setup Wizard and publishing consumer sees
119 * the same capability decision.
120 *
121 * @return bool True when Booking Calendar must not discover or mutate pages.
122 */
123 public static function is_page_publishing_restricted() {
124 $is_restricted = self::is_live_demo();
125 $site_host = self::get_site_host();
126 $request_host = self::get_request_host();
127
128 /**
129 * Filter whether Booking Calendar page publishing is restricted.
130 *
131 * @since 11.6.0
132 *
133 * @param bool $is_restricted Whether the shared environment policy restricts publishing.
134 * @param string $site_host Normalized WordPress home URL host.
135 * @param string $request_host Normalized request host used only as a fallback.
136 */
137 return function_exists( 'apply_filters' )
138 ? (bool) apply_filters( 'wpbc_publish_booking_form_is_demo_restricted', $is_restricted, $site_host, $request_host )
139 : $is_restricted;
140 }
141
142 /**
143 * Determine whether Booking Calendar may discover and publish WordPress pages.
144 *
145 * @return bool True when page publishing is available.
146 */
147 public static function allows_page_publishing() {
148 return ! self::is_page_publishing_restricted();
149 }
150
151 /**
152 * Determine whether Setup Wizard may collect Business details.
153 *
154 * @return bool True on customer and internal test installations.
155 */
156 public static function allows_setup_business_details() {
157 return ! self::is_live_demo() && ! self::is_playground();
158 }
159
160 /**
161 * Determine whether Setup Wizard may send its optional summary email.
162 *
163 * @return bool True when the Business details consent step is available.
164 */
165 public static function allows_setup_summary_email() {
166 return self::allows_setup_business_details();
167 }
168
169 /**
170 * Determine whether the environment permits automatic Setup onboarding.
171 *
172 * Request-specific restrictions such as network administration, bulk
173 * activation, and iframe requests remain the activation coordinator's
174 * responsibility.
175 *
176 * @return bool True when the environment permits automatic onboarding.
177 */
178 public static function allows_automatic_setup_onboarding() {
179 return ! self::is_live_demo() && ! self::is_playground();
180 }
181
182 /**
183 * Return the normalized WordPress home host.
184 *
185 * @return string Normalized host, or an empty string when unavailable.
186 */
187 public static function get_site_host() {
188 if ( ! function_exists( 'home_url' ) ) {
189 return '';
190 }
191
192 return self::normalize_host( home_url( '/' ) );
193 }
194
195 /**
196 * Return the normalized current request host.
197 *
198 * This value is only a fallback when WordPress has no configured home host.
199 * Proxy-only forwarding headers are intentionally ignored.
200 *
201 * @return string Normalized host, or an empty string outside HTTP.
202 */
203 public static function get_request_host() {
204 if ( empty( $_SERVER['HTTP_HOST'] ) ) {
205 return '';
206 }
207
208 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- normalize_host() validates and reduces the value to a hostname.
209 $request_host = function_exists( 'wp_unslash' ) ? wp_unslash( $_SERVER['HTTP_HOST'] ) : $_SERVER['HTTP_HOST'];
210
211 return self::normalize_host( $request_host );
212 }
213
214 /**
215 * Normalize a URL host or HTTP Host value.
216 *
217 * @param mixed $host Hostname, optionally containing a port or trailing dot.
218 *
219 * @return string Lowercase hostname, or an empty string when invalid.
220 */
221 public static function normalize_host( $host ) {
222 $host = trim( strtolower( (string) $host ) );
223 if ( '' === $host ) {
224 return '';
225 }
226
227 $host_url = preg_match( '#^[a-z][a-z0-9+.-]*://#i', $host ) ? $host : 'http://' . ltrim( $host, '/' );
228 $normalized_host = function_exists( 'wp_parse_url' )
229 ? wp_parse_url( $host_url, PHP_URL_HOST )
230 : parse_url( $host_url, PHP_URL_HOST );
231 if ( ! is_string( $normalized_host ) ) {
232 return '';
233 }
234
235 return strtolower( rtrim( $normalized_host, '.' ) );
236 }
237
238 /**
239 * Determine whether a host is one of the managed public live demos.
240 *
241 * Exact matching prevents internal, customer, and lookalike subdomains from
242 * inheriting demo restrictions merely because their names share a suffix.
243 *
244 * @param string $host Normalized or unnormalized hostname.
245 *
246 * @return bool True for a managed public live-demo host.
247 */
248 public static function is_public_live_demo_host( $host ) {
249 $host = self::normalize_host( $host );
250
251 /**
252 * Filter the exact public live-demo host allow-list.
253 *
254 * @since 11.9.0
255 *
256 * @param string[] $live_demo_hosts Normalized public live-demo hosts.
257 */
258 $live_demo_hosts = array(
259 'personal.wpbookingcalendar.com',
260 'bs.wpbookingcalendar.com',
261 'bm.wpbookingcalendar.com',
262 'bl.wpbookingcalendar.com',
263 'multiuser.wpbookingcalendar.com',
264 'personaltest.wpbookingcalendar.com',
265 'bstest.wpbookingcalendar.com',
266 'bmtest.wpbookingcalendar.com',
267 'bltest.wpbookingcalendar.com',
268 'multiusertest.wpbookingcalendar.com',
269 );
270 if ( function_exists( 'apply_filters' ) ) {
271 $live_demo_hosts = apply_filters( 'wpbc_environment_public_live_demo_hosts', $live_demo_hosts );
272 }
273 $live_demo_hosts = self::normalize_host_list( $live_demo_hosts );
274
275 return '' !== $host && in_array( $host, $live_demo_hosts, true );
276 }
277
278 /**
279 * Determine whether a host is an explicitly identified internal test site.
280 *
281 * Internal test sites intentionally keep standard publishing and onboarding
282 * capabilities. This explicit identity prevents future suffix-based logic
283 * from accidentally treating the Free test site as a public demo.
284 *
285 * @param string $host Normalized or unnormalized hostname.
286 *
287 * @return bool True for an internal test host.
288 */
289 public static function is_internal_test_host( $host ) {
290 $host = self::normalize_host( $host );
291
292 /**
293 * Filter the exact internal test host allow-list.
294 *
295 * @since 11.9.0
296 *
297 * @param string[] $internal_test_hosts Normalized internal test hosts.
298 */
299 $internal_test_hosts = array(
300 'freetest.wpbookingcalendar.com',
301 'beta',
302 );
303 if ( function_exists( 'apply_filters' ) ) {
304 $internal_test_hosts = apply_filters( 'wpbc_environment_internal_test_hosts', $internal_test_hosts );
305 }
306 $internal_test_hosts = self::normalize_host_list( $internal_test_hosts );
307
308 return '' !== $host && in_array( $host, $internal_test_hosts, true );
309 }
310
311 /**
312 * Normalize and deduplicate a filtered hostname list.
313 *
314 * @param mixed $hosts Candidate hostname list.
315 *
316 * @return string[] Valid normalized hostnames.
317 */
318 private static function normalize_host_list( $hosts ) {
319 $normalized_hosts = array();
320
321 foreach ( is_array( $hosts ) ? $hosts : array() as $host ) {
322 if ( ! is_scalar( $host ) ) {
323 continue;
324 }
325
326 $normalized_host = self::normalize_host( $host );
327 if ( '' !== $normalized_host ) {
328 $normalized_hosts[] = $normalized_host;
329 }
330 }
331
332 return array_values( array_unique( $normalized_hosts ) );
333 }
334 }
335