PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / trunk
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! vtrunk
3.8.0 3.7.5 3.7.4 3.7.3 3.7.2 1-final 3.7.1 3.7.0 3.6.8 3.6.7 3.6.6 3.6.5 3.6.4 3.6.3 3.6.2 3.6.1 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 All 112 releases
templately / includes / Utils / Options.php

Options.php in Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! trunk, at includes/Utils/Options.php

291 lines 7.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Templately\Utils;
4
5 use function get_option;
6 use function update_option;
7 use function get_user_meta;
8 use function update_user_meta;
9 use function get_current_user_id;
10
11 class Options extends Base {
12 /**
13 * Pin every derived read/write to the acting user, bypassing the
14 * global-login fallback in user_id().
15 *
16 * @var bool
17 */
18 private $force_current_user = false;
19
20 /**
21 * Get the current user ID.
22 *
23 * Resolved live on every call rather than cached at construction time:
24 * `Options` is a request-lifetime singleton (`Base::get_instance()`), and
25 * something in Templately's own bootstrap (e.g. `Admin`/`Settings`)
26 * constructs it during `plugins_loaded` — before WordPress resolves the
27 * REST Application-Password current user (which only happens later, when
28 * the REST server actually dispatches the route). Caching `
29 * get_current_user_id()` at construction froze it at `0` for the rest of
30 * the request on any headless (non-cookie) REST/MCP call, so every later
31 * `Options` read looked up user `0`'s meta instead of the real acting
32 * user's — reporting "session expired" even for a genuinely connected
33 * account. `get_current_user_id()` is itself cheap (it just reads WP
34 * core's own already-resolved `$current_user` global), so there is no
35 * reason to cache it a second time here.
36 *
37 * @return int
38 */
39 public function current_user_id(): int {
40 return get_current_user_id();
41 }
42
43 /**
44 * Whether the current user has an API key set — computed live for the
45 * same reason as {@see current_user_id()}, not cached.
46 *
47 * @return boolean
48 */
49 private function has_api(): bool {
50 return ! empty( $this->get( 'api_key', '', $this->current_user_id() ) );
51 }
52
53 /**
54 * Can a user link another templately account in a setup?.
55 * @return boolean
56 */
57 public function link_account(): bool {
58 return $this->who_am_i() === 'link' && ! $this->has_api();
59 }
60
61 public function unlink_account(): bool {
62 return ( $this->who_am_i() === 'link' || $this->who_am_i() === 'local' ) && $this->has_api();
63 }
64
65 /**
66 * Get determined who am I.
67 * @return string
68 */
69 public function who_am_i(): string {
70 $_who_am_i = 'local';
71 $current_user = $this->current_user_id();
72
73 if( $this->is_global() > 0 && $this->is_global() === $current_user ) {
74 $_who_am_i = 'global';
75 }
76
77 if( $this->is_global() > 0 && $this->is_global() !== $current_user ) {
78 $_who_am_i = 'link';
79 }
80
81 if( $this->is_global() == 0 ) {
82 $_who_am_i = 'local';
83 }
84
85 return $_who_am_i;
86 }
87
88 /**
89 * Pin the acting user as the target for every derived read/write.
90 *
91 * @param bool $force Whether to force the current user.
92 * @return Options
93 */
94 public function use_current_user( bool $force = true ): Options {
95 $this->force_current_user = $force;
96
97 return $this;
98 }
99
100 /**
101 * Get user id determine dynamically
102 * @return integer
103 */
104 private function user_id(): int {
105 if ( $this->force_current_user ) {
106 return $this->current_user_id();
107 }
108
109 $_who_am_i = $this->who_am_i();
110
111 if( ! empty( $_SERVER['REQUEST_URI'] ) ) {
112 // FR-003: in 'link' mode the login-endpoint override targets the
113 // current user so they can store their own credentials. Detect it
114 // with a substring match on '/login' so REST paths such as
115 // `/wp-json/templately/v1/login` are covered — including requests
116 // with NO query string, which the former last-path-segment check
117 // (substr up to '?', which collapses to '' when there is no '?')
118 // never matched. `strpos(...) !== false` keeps the PHP 7.4 floor
119 // (`str_contains()` is PHP 8.0+).
120 $uri = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) );
121 if( $_who_am_i === 'link' && strpos( $uri, '/login' ) !== false ) {
122 return $this->current_user_id();
123 }
124 }
125
126 if( $_who_am_i === 'link' && $this->has_api() ) {
127 return $this->current_user_id();
128 }
129
130 return $_who_am_i === 'local' ? $this->current_user_id() : $this->is_global();
131 }
132
133 /**
134 * Globally logged in and the User ID of globally logged-in user.
135 * @return integer
136 */
137 public function is_global(): int {
138 return intval( get_option('_templately_global_login', 0) );
139 }
140
141 /**
142 * Set global login flag
143 * @return boolean
144 */
145 public static function set_global_login(): bool {
146 return update_option('_templately_global_login', get_current_user_id(), 'no');
147 }
148
149 /**
150 * Remove global login flag
151 * @return boolean
152 */
153 public function remove_global_login(): bool {
154 return delete_option( '_templately_global_login' );
155 }
156
157 public function is_globally_signed(): bool {
158 return $this->who_am_i() !== 'local';
159 }
160
161 public function signed_as_global(): bool {
162 return $this->current_user_id() === $this->is_global();
163 }
164
165 /**
166 * Set optional user meta or option data
167 *
168 * @param string $key
169 * @param mixed $value
170 * @param null $user_id
171 * @return boolean
172 */
173 public function set( $key, $value, $user_id = null ): bool {
174 $key = '_templately_' . $key;
175
176 return $this->update_user_meta( $user_id, $key, $value );
177 }
178
179 /**
180 * Get optional user meta or option data
181 *
182 * @param string $key
183 * @param mixed $default
184 * @return mixed
185 */
186 public function get( $key, $default = false, $user_id = null ){
187 $key = '_templately_' . $key;
188 $_user_meta = $this->get_user_meta( $user_id, $key, true );
189 // '' (get_user_meta) and false (get_user_option) are the MISSING sentinels —
190 // but 0, '0' and [] are legitimate stored values and must not collapse to
191 // the default (the same falsy-swallow bug fixed in API::get_param()).
192 return ( '' === $_user_meta || false === $_user_meta ) ? $default : $_user_meta;
193 }
194
195 /**
196 * Remove options data or user meta
197 *
198 * @param string $key
199 * @return Options
200 */
201 public function remove( string $key ): Options {
202 $key = '_templately_' . $key;
203 $this->delete_user_meta( $key );
204
205 return $this;
206 }
207
208 public function get_user_meta( $user_id, $key = '', $single = false ) {
209 $user_id = is_null( $user_id ) ? $this->user_id() : $user_id;
210
211 if( ! is_multisite() ) {
212 return get_user_meta( $user_id, $key, $single);
213 }
214
215 return get_user_option( $key, $user_id );
216 }
217
218 public function update_user_meta($user_id, $meta_key, $meta_value) {
219 if ( is_null( $user_id ) ) {
220 if ( ! $this->can_write() ) {
221 return false;
222 }
223
224 $user_id = $this->user_id();
225 }
226
227 if( ! is_multisite() ) {
228 return update_user_meta( $user_id, $meta_key, $meta_value );
229 }
230
231 return update_user_option( $user_id, $meta_key, $meta_value, $this->_is_global() );
232 }
233
234 public function delete_user_meta( $meta_key ): bool {
235 if ( ! $this->can_write() ) {
236 return false;
237 }
238
239 if( ! is_multisite() ) {
240 return delete_user_meta( $this->user_id(), $meta_key );
241 }
242
243 return delete_user_option( $this->user_id(), $meta_key, $this->_is_global() );
244 }
245
246 /**
247 * Whether the current request may write to a derived user target.
248 *
249 * Reads retain the global-login fallback for unauthenticated cloud callbacks,
250 * but an anonymous request must never write through it to the administrator.
251 *
252 * @return bool
253 */
254 private function can_write(): bool {
255 return $this->current_user_id() > 0;
256 }
257
258 private function _is_global() {
259 return apply_filters( 'templately_multisite_is_global', false );
260 }
261
262 /**
263 * Get option data
264 *
265 * @since 2.0.1
266 *
267 * @param string $key
268 * @param mixed $default
269 *
270 * @return mixed
271 */
272 public function get_option( $key, $default = false ){
273 return get_option( $key, $default );
274 }
275
276 /**
277 * Update option data
278 *
279 * @since 2.0.1
280 *
281 * @param string $key
282 * @param mixed $value
283 * @param string $autoload
284 *
285 * @return bool
286 */
287 public function update_option( $key, $value, $autoload = 'no' ): bool {
288 return update_option( $key, $value, $autoload );
289 }
290 }
291