PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.6.25
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.6.25
2.7.1 2.7.2 2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 All 141 releases
metasync / includes / class-metasync-bookingpress-compat.php

class-metasync-bookingpress-compat.php in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.6.25, at includes/class-metasync-bookingpress-compat.php

170 lines 5.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * BookingPress front-end session compatibility.
4 *
5 * BookingPress hooks `init` at priority 1 and calls session_start() on every
6 * non-admin request. The PHPSESSID cookie this sets on every response makes
7 * SiteGround (and most hosts) skip their page cache for the whole site, so
8 * no public page is ever served from cache — everything renders in full PHP
9 * on every visit.
10 *
11 * Nothing in BookingPress depends on that global session:
12 *
13 * - The spam-protection captcha it was built for writes its session value
14 * from an admin-ajax endpoint, where BookingPress's own is_admin() guard
15 * prevents the session from starting, so the write is discarded; and the
16 * validation filter that would read it is registered nowhere (its only
17 * add_filter line ships commented out in their plugin). Current versions
18 * exchange the captcha over transients and nonces instead.
19 * - The remaining session uses are version-gated legacy support for old
20 * releases, living inside AJAX handlers that call session_start()
21 * themselves — except Pro's cart handshake, which does ride on the
22 * front-end session, but only for visitors holding a
23 * bookingpress_cart_id cookie (set by the separate cart module). Those
24 * visitors keep the session; see the cookie guard below.
25 *
26 * This shim removes the global session start on public HTML requests so host
27 * page caching can engage again. Admin, AJAX, cron, CLI and REST requests
28 * are untouched, and any code that genuinely needs a session still starts
29 * its own.
30 *
31 * @package MetaSync
32 * @subpackage MetaSync/includes
33 * @since 2.6.22
34 */
35
36 if (!defined('ABSPATH')) {
37 exit; # Exit if accessed directly
38 }
39
40 class Metasync_BookingPress_Compat
41 {
42 /**
43 * Option value that disables the shim ("Auto" keeps it on).
44 */
45 const DISABLED_VALUE = 'off';
46
47 /**
48 * Runs on `init` at priority 0, ahead of BookingPress's priority-1
49 * session start, and unhooks it for this request.
50 *
51 * @return void
52 */
53 public static function neutralize_bookingpress_session()
54 {
55 if (self::is_disabled_by_setting() || !self::is_public_html_request()) {
56 return;
57 }
58 # Pro's cart handshake (cart-cookie expiry flag and cart prefill) rides
59 # on the front-end session, but only for visitors the separate cart
60 # module has given a bookingpress_cart_id cookie. Leave the session in
61 # place for them so the handshake keeps working; once their cookie is
62 # expired the shim engages again on its own.
63 if (!empty($_COOKIE['bookingpress_cart_id'])) {
64 return;
65 }
66 self::remove_spam_protection_session_hook();
67 }
68
69 /**
70 * The shim is on by default; only an explicit "off" disables it.
71 *
72 * @return bool True when the shim must not touch anything.
73 */
74 private static function is_disabled_by_setting()
75 {
76 $options = get_option('metasync_options', array());
77 $mode = $options['general']['bookingpress_session_compat'] ?? 'auto';
78 return $mode === self::DISABLED_VALUE;
79 }
80
81 /**
82 * Only public page renders matter for host caching; every other request
83 * context is left exactly as WordPress finds it.
84 *
85 * @return bool True for front-end HTML requests.
86 */
87 private static function is_public_html_request()
88 {
89 if (is_admin() || wp_doing_ajax() || wp_doing_cron()) {
90 return false;
91 }
92 # WP_CLI is only ever defined (as true) by wp-cli itself, so the bare
93 # defined() check carries the meaning; referencing the constant value
94 # trips static analysis, which resolves the stubbed value to always-true.
95 if (defined('WP_CLI')) {
96 return false;
97 }
98 if (defined('REST_REQUEST') && REST_REQUEST) {
99 return false;
100 }
101 return true;
102 }
103
104 /**
105 * Remove bookingpress_spam_protection::bookingpress_start_session from
106 * the init hook.
107 *
108 * The preferred path uses the global instance BookingPress exposes; a
109 * registry scan follows as fallback to catch renamed globals, subclasses
110 * or a changed registration priority.
111 *
112 * @return bool True when the callback was found and removed.
113 */
114 private static function remove_spam_protection_session_hook()
115 {
116 $removed = false;
117
118 if (!empty($GLOBALS['bookingpress_spam_protection']) && is_object($GLOBALS['bookingpress_spam_protection'])) {
119 $removed = remove_action(
120 'init',
121 array($GLOBALS['bookingpress_spam_protection'], 'bookingpress_start_session'),
122 1
123 );
124 }
125
126 if ($removed) {
127 return true;
128 }
129
130 if (!isset($GLOBALS['wp_filter']['init'])) {
131 return false;
132 }
133
134 $init_hook = &$GLOBALS['wp_filter']['init'];
135
136 # WP_Hook objects (WP 4.7+) keep callbacks in a public property; the
137 # plain-array shape covers legacy WP and unit-test registries alike.
138 if ($init_hook instanceof WP_Hook) {
139 $callbacks = &$init_hook->callbacks;
140 } elseif (is_array($init_hook)) {
141 $callbacks = &$init_hook;
142 } else {
143 return false;
144 }
145
146 if (empty($callbacks)) {
147 return false;
148 }
149
150 foreach ($callbacks as $priority => $entries) {
151 if (!is_array($entries)) {
152 continue;
153 }
154 foreach ($entries as $callback_id => $entry) {
155 $fn = is_array($entry) && isset($entry['function']) ? $entry['function'] : $entry;
156 if (
157 is_array($fn) && count($fn) === 2 && is_object($fn[0])
158 && is_a($fn[0], 'bookingpress_spam_protection')
159 && $fn[1] === 'bookingpress_start_session'
160 ) {
161 unset($callbacks[$priority][$callback_id]);
162 return true;
163 }
164 }
165 }
166
167 return false;
168 }
169 }
170