PluginProbe
Restrict User Access – Ultimate Membership & Content Protection / 2.8
Restrict User Access – Ultimate Membership & Content Protection v2.8
trunk 1.3 2.0 2.1.3 2.2.3 2.3.2 2.4 2.4.1 2.4.2 2.4.3 2.5 2.6 2.6.1 2.7 2.7.1 2.8 2.8.1
restrict-user-access / level.php

level.php in Restrict User Access – Ultimate Membership & Content Protection 2.8, at level.php

463 lines 13.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Restrict User Access
4 * @author Joachim Jensen <joachim@dev.institute>
5 * @license GPLv3
6 * @copyright 2024 by Joachim Jensen
7 */
8
9 defined('ABSPATH') || exit;
10
11 /**
12 * @deprecated
13 */
14 final class RUA_Level_Manager
15 {
16 /**
17 * Metadata
18 *
19 * @var WPCACollection
20 */
21 private $metadata;
22
23 public function __construct()
24 {
25 $this->add_actions();
26 $this->add_filters();
27 }
28
29 /**
30 * Add callbacks to actions queue
31 *
32 * @since 0.5
33 */
34 protected function add_actions()
35 {
36 add_action(
37 'template_redirect',
38 [$this,'authorize_access']
39 );
40 }
41
42 /**
43 * Add callbacks to filters queue
44 *
45 * @since 0.5
46 */
47 protected function add_filters()
48 {
49 if (!is_admin()) {
50 add_filter(
51 'rua/auth/page-no-access',
52 [$this, 'set_multilingual_non_member_action_page'],
53 10,
54 2
55 );
56 }
57 }
58
59 /**
60 * Get level by name
61 *
62 * @since 0.6
63 * @param string $name
64 * @return WP_Post|bool
65 */
66 public function get_level_by_name($name)
67 {
68 $all_levels = RUA_App::instance()->get_levels();
69 foreach ($all_levels as $id => $level) {
70 if ($level->post_name == $name && $level->post_status == RUA_App::STATUS_ACTIVE) {
71 return $level;
72 }
73 }
74 return false;
75 }
76
77 /**
78 * Get instance of metadata manager
79 *
80 * @since 1.0
81 * @return WPCACollection
82 */
83 public function metadata()
84 {
85 if (!$this->metadata) {
86 $this->_init_metadata();
87 }
88 return $this->metadata;
89 }
90
91 /**
92 * Create and populate metadata fields
93 *
94 * @since 0.1
95 * @return void
96 */
97 private function _init_metadata()
98 {
99 $options = [
100 new WPCAMeta(
101 'handle',
102 _x('Non-Member Action', 'option', 'restrict-user-access'),
103 0,
104 'select',
105 [
106 0 => __('Redirect', 'restrict-user-access'),
107 1 => __('Tease & Include', 'restrict-user-access')
108 ],
109 __('Redirect to another page or show teaser.', 'restrict-user-access')
110 ),
111 new WPCAMeta(
112 'page',
113 __('Page'),
114 0,
115 'select',
116 [],
117 __('Page to redirect to or display content from under teaser.', 'restrict-user-access')
118 ),
119 new WPCAMeta(
120 'duration',
121 __('Duration', 'restrict-user-access'),
122 'day',
123 'select',
124 [
125 'day' => __('Day(s)', 'restrict-user-access'),
126 'week' => __('Week(s)', 'restrict-user-access'),
127 'month' => __('Month(s)', 'restrict-user-access'),
128 'year' => __('Year(s)', 'restrict-user-access')
129 ],
130 __('Set to 0 for unlimited.', 'restrict-user-access')
131 ),
132 new WPCAMeta(
133 'caps',
134 __('Capabilities', 'restrict-user-access'),
135 [],
136 '',
137 [],
138 '',
139 [$this,'sanitize_capabilities']
140 ),
141 new WPCAMeta(
142 'hide_admin_bar',
143 __('Hide Admin Toolbar', 'restrict-user-access'),
144 '',
145 'checkbox',
146 [],
147 ''
148 ),
149 new WPCAMeta(
150 'default_access',
151 __('Deny Access to Unprotected Content', 'restrict-user-access'),
152 1,
153 'checkbox',
154 [],
155 '',
156 [$this, 'sanitize_checkbox_option']
157 ),
158 new WPCAMeta(
159 'admin_access',
160 __('Deny Access to Admin Area', 'restrict-user-access'),
161 1,
162 'checkbox',
163 [],
164 '',
165 [$this, 'sanitize_checkbox_option']
166 ),
167 new WPCAMeta(
168 'member_automations',
169 __('Member Automation', 'restrict-user-access'),
170 [],
171 'select',
172 [],
173 ''
174 )
175 ];
176
177 $this->metadata = new WPCACollection();
178 foreach ($options as $option) {
179 $this->metadata->put($option->get_id(), $option);
180 }
181
182 apply_filters('rua/metadata', $this->metadata);
183 }
184
185 /**
186 * @param array|mixed $value
187 *
188 * @return array
189 */
190 public function sanitize_capabilities($value)
191 {
192 $existing_capabilities = get_post_meta($_POST['post'], WPCACore::PREFIX . 'caps', false);
193
194 if ((is_array($value) && !empty($value)) || !empty($existing_capabilities)) {
195 $valid_values = [
196 -1 => true,
197 0 => true,
198 1 => true
199 ];
200 $value = (array) $value;
201 $user = rua_get_user();
202 if (!$user->has_global_access()) {
203 $value = array_intersect_key($value, $user->get_caps());
204 }
205
206 $value = array_merge($existing_capabilities, $value);
207 $inherited_caps = isset($_POST['inherited_caps']) ? $_POST['inherited_caps'] : [];
208 foreach ($value as $name => $cap) {
209 if (is_integer($name) || !isset($valid_values[$cap])) {
210 unset($value[$name]);
211 }
212 /**
213 * do not save if:
214 * - value is equal to inherited
215 * - no inherited value and unsetting
216 */
217 elseif (isset($inherited_caps[$name]) ? $inherited_caps[$name] == $cap
218 : $cap == -1) {
219 unset($value[$name]);
220 }
221 }
222 }
223 return $value;
224 }
225
226 /**
227 * ensure "0" is stored when unchecked
228 *
229 * @param mixed $value
230 * @return mixed
231 */
232 public function sanitize_checkbox_option($value)
233 {
234 if (empty($value)) {
235 return '0';
236 }
237 return $value;
238 }
239
240 /**
241 * @param string|int $page
242 * @param RUA_User_Interface $rua_user
243 * @return string|int
244 */
245 public function set_multilingual_non_member_action_page($page, $rua_user)
246 {
247 if (!is_numeric($page)) {
248 return $page;
249 }
250
251 if (defined('POLYLANG_VERSION')) {
252 $language_current = pll_current_language();
253 $language_target = $language_current !== false ? $language_current : pll_default_language();
254
255 if ($language_target !== false) {
256 $page_current_language = pll_get_post($page, $language_target);
257 //ensure translated page exists
258 if (!empty($page_current_language)) {
259 return $page_current_language;
260 }
261 }
262 }
263
264 return $page;
265 }
266
267 /**
268 * Get conditional restrictions
269 * and authorize access for user
270 *
271 * @since 0.1
272 * @return void
273 */
274 public function authorize_access()
275 {
276 $rua_user = rua_get_user();
277
278 if ($rua_user->has_global_access()) {
279 return;
280 }
281
282 $authorized_levels = WPCACore::get_posts(RUA_App::TYPE_RESTRICT);
283
284 if ($authorized_levels === false) {
285 return;
286 }
287
288 $user_levels = array_flip(array_reverse($rua_user->get_level_ids()));
289 $kick = false;
290
291 //does user have level to view unrestricted content by default?
292 foreach ($user_levels as $level => $val) {
293 if ($this->metadata()->get('default_access')->get_data($level, true)) {
294 $kick = false;
295 break;
296 }
297 $kick = $level;
298 }
299
300 //does user have authorized level?
301 foreach ($authorized_levels as $level) {
302 if (isset($user_levels[$level->ID])) {
303 $kick = false;
304 break;
305 }
306 $kick = $level->ID;
307 }
308
309 if (!empty($authorized_levels) && $kick === false && $rua_user->get_id() !== 0) {
310 $conditions = WPCACore::get_conditions(RUA_App::TYPE_RESTRICT);
311 foreach ($conditions as $condition => $level) {
312 //Check post type
313 if (!isset($authorized_levels[$level])) {
314 continue;
315 }
316
317 $drip = get_post_meta($condition, RUA_App::META_PREFIX . 'opt_drip', true);
318 //Restrict access to dripped content
319 if ($drip > 0 && $rua_user->has_level($level)) {
320 //@todo if extended level drips content, use start date
321 //of level user is member of
322 $start = $rua_user->level_memberships()->get($level)->get_start();
323 if ($start > 0) {
324 $drip_time = strtotime('+' . $drip . ' days 00:00', $start);
325 $should_drip = apply_filters(
326 'rua/auth/content-drip',
327 time() <= $drip_time,
328 $rua_user,
329 $level
330 );
331 if ($should_drip) {
332 $kick = $level;
333 continue;
334 }
335 }
336 }
337 $kick = false;
338 break;
339 }
340 }
341
342 $kick = apply_filters('rua/auth/content-access', $kick, $rua_user);
343 if ($kick === false || $kick === null) {
344 return;
345 }
346
347 $action = is_archive() || (is_home() && !is_page()) ? 0 : $this->metadata()->get('handle')->get_data($kick);
348
349 self::$page = apply_filters('rua/auth/page-no-access', $this->metadata()->get('page')->get_data($kick), $rua_user);
350 switch ($action) {
351 case 0:
352 $redirect = '';
353
354 $current_path = remove_query_arg('redirect_to', add_query_arg(null, null));
355 $parts = parse_url(get_site_url());
356 $pos = isset($parts['path']) ? stripos($current_path, $parts['path']) : false;
357 if ($pos !== false) {
358 $relative_path = substr($current_path, $pos + strlen($parts['path']));
359 } else {
360 $relative_path = $current_path;
361 }
362
363 if (is_numeric(self::$page)) {
364 if (self::$page != get_the_ID()) {
365 $redirect = get_permalink(self::$page);
366 }
367 } else {
368 /**
369 * WP always appends /
370 * also check case where non-member action does not have it,
371 * which can cause infinite loop
372 */
373 if ($relative_path != self::$page && $relative_path != self::$page . '/') {
374 $redirect = get_site_url() . self::$page;
375 }
376 }
377
378 //only redirect if current page != redirect page
379 if ($redirect) {
380 wp_safe_redirect(add_query_arg(
381 'redirect_to',
382 urlencode($current_path),
383 $redirect
384 ));
385 exit;
386 }
387 break;
388 case 1:
389 add_filter('the_content', [$this,'content_tease'], 8);
390 break;
391 default: break;
392 }
393 }
394
395 /**
396 * Carry over page from restriction metadata
397 * @var integer
398 */
399 public static $page = false;
400
401 /**
402 * Limit content to only show teaser and
403 * page content from restriction metadata
404 *
405 * @since 0.1
406 * @param string $content
407 * @return string
408 */
409 public function content_tease($content)
410 {
411 if (!in_the_loop()) {
412 return $content;
413 }
414
415 if (get_queried_object_id() !== get_the_ID()) {
416 return $content;
417 }
418
419 if (preg_match('/(<span id="more-[0-9]*"><\/span>)/', $content, $matches)) {
420 $teaser = explode($matches[0], $content, 2);
421 $content = $teaser[0];
422 } else {
423 $content = '';
424 }
425
426 if (is_numeric(self::$page)) {
427 setup_postdata(get_post(self::$page));
428 $content .= get_the_content();
429 wp_reset_postdata();
430 }
431
432 remove_filter('the_content', [$this, 'content_tease'], 8);
433 return $content;
434 }
435
436 /**
437 * Get all capabilities of one or multiple levels
438 *
439 * If you pass an array the order of these levels should be set correctly!
440 * The first level caps will be overwritten by the second etc.
441 *
442 * @since 0.13
443 * @param array|int $levels
444 * @return array
445 */
446 public function get_levels_caps($levels)
447 {
448 $levels = (array) $levels;
449 $caps = [];
450 foreach ($levels as $level) {
451 $level_caps = $this->metadata()->get('caps')->get_data($level, true);
452 foreach ($level_caps as $key => $level_cap) {
453 if ($level_cap > -1) {
454 $caps[$key] = (bool)$level_cap;
455 } else {
456 unset($caps[$key]);
457 }
458 }
459 }
460 return $caps;
461 }
462 }
463