PluginProbe
User Access Manager / 2.2.3
User Access Manager v2.2.3
2.3.20 2.3.19 2.3.18 2.3.17 2.3.16 2.3.15 2.3.14 2.3.13 trunk 0.6 0.6.1 0.6.2 0.7 0.7 Beta 0.7.0.1 0.8 0.8.0.1 0.8.0.2 0.9 0.9.1 0.9.1.1 0.9.1.2 0.9.1.3 0.9.1.4 1.0 All 136 releases
← All changes | src/Controller/Frontend/PostController.php +154 -130 2.3.142.2.3 View file →
@@ -1,5 +1,18 @@
1 1 <?php
2 +/**
3 + * FrontendPostController.php
4 + *
5 + * The FrontendPostController class file.
6 + *
7 + * PHP versions 5
8 + *
9 + * @author Alexander Schneider <alexanderschneider85@gmail.com>
10 + * @copyright 2008-2017 Alexander Schneider
11 + * @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2
12 + * @version SVN: $id$
13 + * @link http://wordpress.org/extend/plugins/user-access-manager/
14 + */
2 15
3 16 declare(strict_types=1);
4 17
5 18 namespace UserAccessManager\Controller\Frontend;
@@ -16,34 +29,59 @@
16 29 use UserAccessManager\UserGroup\UserGroupTypeException;
17 30 use UserAccessManager\Util\Util;
18 31 use UserAccessManager\Wrapper\Php;
19 32 use UserAccessManager\Wrapper\Wordpress;
20 -use WeakMap;
21 33 use WP_Comment;
22 34 use WP_Hook;
23 35 use WP_Post;
24 36 use WP_Query;
25 -use WP_REST_Request;
26 -use WP_REST_Response;
27 37
38 +/**
39 + * Class FrontendPostController
40 + *
41 + * @package UserAccessManager\Controller
42 + */
28 43 class PostController extends ContentController
29 44 {
30 - private array $wordpressFilters = [];
31 - private stdClass|array|null $cachedCounts = [];
45 + /**
46 + * @var Database
47 + */
48 + private $database;
32 49
33 - private WeakMap $posts;
50 + /**
51 + * @var array
52 + */
53 + private $wordpressFilters = [];
34 54
55 + /**
56 + * @var null|stdClass
57 + */
58 + private $cachedCounts = [];
59 +
60 + /**
61 + * PostController constructor.
62 + * @param Php $php
63 + * @param Wordpress $wordpress
64 + * @param WordpressConfig $wordpressConfig
65 + * @param MainConfig $mainConfig
66 + * @param Database $database
67 + * @param Util $util
68 + * @param ObjectHandler $objectHandler
69 + * @param UserHandler $userHandler
70 + * @param UserGroupHandler $userGroupHandler
71 + * @param AccessHandler $accessHandler
72 + */
35 73 public function __construct(
36 74 Php $php,
37 75 Wordpress $wordpress,
38 76 WordpressConfig $wordpressConfig,
39 77 MainConfig $mainConfig,
78 + Database $database,
40 79 Util $util,
41 80 ObjectHandler $objectHandler,
42 81 UserHandler $userHandler,
43 82 UserGroupHandler $userGroupHandler,
44 - AccessHandler $accessHandler,
45 - private Database $database
83 + AccessHandler $accessHandler
46 84 ) {
47 85 parent::__construct(
48 86 $php,
49 87 $wordpress,
@@ -54,17 +92,25 @@
54 92 $userHandler,
55 93 $userGroupHandler,
56 94 $accessHandler
57 95 );
58 -
59 - $this->posts = new WeakMap();
96 + $this->database = $database;
60 97 }
61 98
99 + /**
100 + * Return the wordpress filters.
101 + * @return array
102 + */
62 103 public function getWordpressFilters(): array
63 104 {
64 105 return $this->wordpressFilters;
65 106 }
66 107
108 + /**
109 + * Returns true if the filters are suppressed.
110 + * @param WP_Query $wpQuery
111 + * @return bool
112 + */
67 113 private function filtersSuppressed(WP_Query $wpQuery): bool
68 114 {
69 115 return isset($wpQuery->query_vars['suppress_filters']) === true
70 116 && $wpQuery->query_vars['suppress_filters'] === true;
@@ -69,25 +115,24 @@
69 115 return isset($wpQuery->query_vars['suppress_filters']) === true
70 116 && $wpQuery->query_vars['suppress_filters'] === true;
71 117 }
72 118
73 - private function addExcludedPosts(mixed $postsNotIn, array $excludedPosts): array
74 - {
75 - return array_unique(array_merge((array) $postsNotIn, $excludedPosts));
76 - }
77 -
78 119 /**
120 + * Manipulates the wordpress query object to filter content.
121 + * @param WP_Query $wpQuery The wordpress query object.
79 122 * @throws UserGroupTypeException
80 123 */
81 - public function parseQuery(WP_Query $wpQuery): void
124 + public function parseQuery(WP_Query $wpQuery)
82 125 {
83 126 if ($this->filtersSuppressed($wpQuery) === true) {
84 127 $excludedPosts = $this->accessHandler->getExcludedPosts();
85 128
86 129 if ($excludedPosts !== []) {
87 - $wpQuery->query_vars['post__not_in'] = $this->addExcludedPosts(
88 - $wpQuery->query_vars['post__not_in'] ?? [],
89 - $excludedPosts
130 + $postsNotIn = (isset($wpQuery->query_vars['post__not_in']) === true) ?
131 + $wpQuery->query_vars['post__not_in'] : [];
132 +
133 + $wpQuery->query_vars['post__not_in'] = array_unique(
134 + array_merge($postsNotIn, $excludedPosts)
90 135 );
91 136 }
92 137 }
93 138 }
@@ -92,9 +137,11 @@
92 137 }
93 138 }
94 139
95 140 /**
141 + * Extracts the user access manager filters and returns true if it was successful.
96 142 * @param WP_Hook[] $filters
143 + * @return bool
97 144 */
98 145 private function extractOwnFilters(array $filters): bool
99 146 {
100 147 if (isset($filters['the_posts']->callbacks[10]) === true) {
@@ -112,8 +159,16 @@
112 159
113 160 return false;
114 161 }
115 162
163 + /**
164 + * If filters are suppressed we still want to filter posts, so we have to turn the suppression off,
165 + * remove all other filters than the ones from the user access manager and store them to restore
166 + * them later.
167 + * @param array|null $posts
168 + * @param WP_Query $query
169 + * @return null|array
170 + */
116 171 public function postsPreQuery(?array $posts, WP_Query $query): ?array
117 172 {
118 173 if ($this->filtersSuppressed($query) === true) {
119 174 $filters = $this->wordpress->getFilters();
@@ -133,9 +188,12 @@
133 188
134 189 return $posts;
135 190 }
136 191
137 - private function restoreFilters(): void
192 + /**
193 + * Restores the filters to normal.
194 + */
195 + private function restoreFilters()
138 196 {
139 197 if (count($this->wordpressFilters) > 0) {
140 198 $filters = $this->wordpress->getFilters();
141 199
@@ -147,9 +205,14 @@
147 205 $this->wordpressFilters = [];
148 206 }
149 207 }
150 208
151 - private function getPost(mixed $post): bool|WP_Post
209 + /**
210 + * Tries to get the post from the given mixed data.
211 + * @param mixed $post
212 + * @return false|WP_Post
213 + */
214 + private function getPost($post)
152 215 {
153 216 if ($post instanceof WP_post) {
154 217 return $post;
155 218 } elseif (is_int($post) === true) {
@@ -160,8 +223,13 @@
160 223
161 224 return false;
162 225 }
163 226
227 + /**
228 + * Processes the post content and searches for the more tag.
229 + * @param WP_Post $post
230 + * @return string
231 + */
164 232 private function processPostContent(WP_Post $post): string
165 233 {
166 234 $uamPostContent = htmlspecialchars_decode($this->mainConfig->getPostTypeContent($post->post_type));
167 235
@@ -174,17 +242,20 @@
174 242 return stripslashes($uamPostContent);
175 243 }
176 244
177 245 /**
246 + * Modifies the content of the post by the given settings.
247 + * @param WP_Post $post The current post.
248 + * @return null|WP_Post
178 249 * @throws UserGroupTypeException
179 250 */
180 - private function processPost(WP_Post $post): WP_Post|bool
251 + private function processPost(WP_Post $post): ?WP_Post
181 252 {
182 253 $post->post_title .= $this->adminOutput($post->post_type, $post->ID);
183 254
184 255 if ($this->accessHandler->checkObjectAccess($post->post_type, $post->ID) === false) {
185 256 if ($this->removePostFromList($post->post_type) === true) {
186 - return false;
257 + return null;
187 258 }
188 259
189 260 $post->post_content = $this->processPostContent($post);
190 261
@@ -200,19 +271,13 @@
200 271 return $post;
201 272 }
202 273
203 274 /**
275 + * Filters the raw posts.
276 + * @param array $rawPosts
277 + * @return array
204 278 * @throws UserGroupTypeException
205 279 */
206 - private function getProcessedPost(WP_Post $post): ?WP_Post
207 - {
208 - $post = $this->posts[$post] ??= $this->processPost($post);
209 - return $post === false ? null : $post;
210 - }
211 -
212 - /**
213 - * @throws UserGroupTypeException
214 - */
215 280 private function filterRawPosts(array $rawPosts): array
216 281 {
217 282 $filteredPosts = [];
218 283
@@ -219,9 +284,9 @@
219 284 foreach ($rawPosts as $rawPost) {
220 285 $post = $this->getPost($rawPost);
221 286
222 287 if ($post !== false) {
223 - $post = $this->getProcessedPost($post);
288 + $post = $this->processPost($post);
224 289
225 290 if ($post !== null) {
226 291 $filteredPosts[] = $post;
227 292 }
@@ -233,14 +298,17 @@
233 298 return $filteredPosts;
234 299 }
235 300
236 301 /**
302 + * The function for the the_posts filter.
303 + * @param array $showPosts The posts.
304 + * @return array
237 305 * @throws UserGroupTypeException
238 306 */
239 - public function showPosts(?array $showPosts = []): ?array
307 + public function showPosts($showPosts = []): array
240 308 {
241 309 if ($this->wordpress->isFeed() === false || $this->mainConfig->protectFeed() === true) {
242 - $showPosts = $this->filterRawPosts((array) $showPosts);
310 + $showPosts = $this->filterRawPosts($showPosts);
243 311 }
244 312
245 313 $this->restoreFilters();
246 314
@@ -247,105 +315,27 @@
247 315 return $showPosts;
248 316 }
249 317
250 318 /**
319 + * The function for the get_pages filter.
251 320 * @param WP_Post[] $rawPages The pages.
321 + * @return array
252 322 * @throws UserGroupTypeException
253 323 */
254 - public function showPages(array $rawPages = []): array
324 + public function showPages($rawPages = []): array
255 325 {
256 326 return $this->filterRawPosts($rawPages);
257 327 }
258 328
259 - private function isSingleObjectRestRequest(mixed $request, WP_Post $post): bool
260 - {
261 - return $request instanceof WP_REST_Request
262 - && $request->get_param('id') !== null
263 - && (int) $request->get_param('id') === (int) $post->ID;
264 - }
265 -
266 - private function setRestField(array &$data, string $field, string $value): void
267 - {
268 - if (array_key_exists($field, $data) === false) {
269 - return;
270 - }
271 -
272 - if (is_array($data[$field]) === true) {
273 - if (array_key_exists('rendered', $data[$field]) === true) {
274 - $data[$field]['rendered'] = $value;
275 - }
276 -
277 - if (array_key_exists('raw', $data[$field]) === true) {
278 - $data[$field]['raw'] = $value;
279 - }
280 -
281 - if (array_key_exists('protected', $data[$field]) === true) {
282 - $data[$field]['protected'] = false;
283 - }
284 - } else {
285 - $data[$field] = $value;
286 - }
287 - }
288 -
289 329 /**
290 - * The_posts / posts_where_paged never run for REST single-item requests,
291 - * which resolve through get_post() directly, so access is enforced here too.
292 - *
330 + * Checks the access of the attached file.
331 + * @param string $file
332 + * @param int $attachmentId
333 + * @return string|false
293 334 * @throws UserGroupTypeException
294 335 */
295 - public function restrictRestResponse(mixed $response, mixed $post = null, mixed $request = null): mixed
336 + public function getAttachedFile(string $file, int $attachmentId)
296 337 {
297 - if (($response instanceof WP_REST_Response) === false
298 - || ($post instanceof WP_Post) === false
299 - || $this->accessHandler->checkObjectAccess($post->post_type, $post->ID) === true
300 - ) {
301 - return $response;
302 - }
303 -
304 - if ($this->removePostFromList($post->post_type) === true
305 - && $this->isSingleObjectRestRequest($request, $post) === true
306 - ) {
307 - return $this->wordpress->getWpError(
308 - 'uam_rest_access_denied',
309 - TXT_UAM_REST_ACCESS_DENIED,
310 - ['status' => $this->wordpress->isUserLoggedIn() === true ? 403 : 401]
311 - );
312 - }
313 -
314 - $restrictedContent = $this->processPostContent($post);
315 - $data = (array) $response->get_data();
316 -
317 - $this->setRestField($data, 'content', $restrictedContent);
318 - $this->setRestField($data, 'excerpt', $restrictedContent);
319 -
320 - if ($this->mainConfig->hidePostTypeTitle($post->post_type) === true) {
321 - $this->setRestField($data, 'title', $this->mainConfig->getPostTypeTitle($post->post_type));
322 - }
323 -
324 - $response->set_data($data);
325 -
326 - return $response;
327 - }
328 -
329 - /**
330 - * @throws UserGroupTypeException
331 - */
332 - public function excludeRestrictedPostsFromRestQuery(array $queryArgs): array
333 - {
334 - $excludedPosts = $this->accessHandler->getExcludedPosts();
335 -
336 - if ($excludedPosts !== []) {
337 - $queryArgs['post__not_in'] = $this->addExcludedPosts($queryArgs['post__not_in'] ?? [], $excludedPosts);
338 - }
339 -
340 - return $queryArgs;
341 - }
342 -
343 - /**
344 - * @throws UserGroupTypeException
345 - */
346 - public function getAttachedFile(string $file, int|string|null $attachmentId): bool|string
347 - {
348 338 $isImage = (bool) preg_match('/(?i)\.(jpg|jpeg|jpe|png|gif)$/', $file);
349 339
350 340 if ($isImage === false && $this->mainConfig->lockFile() === true) {
351 341 $hasAccess = $this->accessHandler->checkObjectAccess(ObjectHandler::ATTACHMENT_OBJECT_TYPE, $attachmentId);
@@ -355,8 +345,12 @@
355 345 return $file;
356 346 }
357 347
358 348 /**
349 + * Adds the excluded posts filter to the given query.
350 + * @param string $query
351 + * @param string $table
352 + * @return string
359 353 * @throws UserGroupTypeException
360 354 */
361 355 private function addQueryExcludedPostFilter(string $query, string $table): string
362 356 {
@@ -362,10 +356,10 @@
362 356 {
363 357 $excludedPosts = $this->accessHandler->getExcludedPosts();
364 358
365 359 if ($excludedPosts !== []) {
366 - $excludedPostsStr = implode(', ', array_map('intval', $excludedPosts));
367 - $query .= " AND $table.ID NOT IN ($excludedPostsStr) ";
360 + $excludedPostsStr = implode(', ', $excludedPosts);
361 + $query .= " AND {$table}.ID NOT IN ($excludedPostsStr) ";
368 362 }
369 363
370 364 return $query;
371 365 }
@@ -370,8 +364,11 @@
370 364 return $query;
371 365 }
372 366
373 367 /**
368 + * The function for the posts_where_paged filter.
369 + * @param string $query The where sql statement.
370 + * @return string
374 371 * @throws UserGroupTypeException
375 372 */
376 373 public function showPostSql(string $query): string
377 374 {
@@ -378,8 +375,12 @@
378 375 return $this->addQueryExcludedPostFilter($query, $this->database->getPostsTable());
379 376 }
380 377
381 378 /**
379 + * The function for the get_previous_post_where and
380 + * the get_next_post_where filter.
381 + * @param string $query The current sql string.
382 + * @return string
382 383 * @throws UserGroupTypeException
383 384 */
384 385 public function showNextPreviousPost(string $query): string
385 386 {
@@ -385,15 +386,22 @@
385 386 {
386 387 return $this->addQueryExcludedPostFilter($query, 'p');
387 388 }
388 389
390 + /**
391 + * Returns the post count query.
392 + * @param array $excludedPosts
393 + * @param string $type
394 + * @param string $perm
395 + * @return string
396 + */
389 397 private function getPostCountQuery(array $excludedPosts, string $type, string $perm): string
390 398 {
391 - $excludedPosts = implode(', ', array_map('intval', $excludedPosts));
392 - $query = "SELECT post_status, COUNT(*) AS num_posts
393 - FROM {$this->database->getPostsTable()}
399 + $excludedPosts = implode('\', \'', $excludedPosts);
400 + $query = "SELECT post_status, COUNT(*) AS num_posts
401 + FROM {$this->database->getPostsTable()}
394 402 WHERE post_type = %s
395 - AND ID NOT IN ($excludedPosts)";
403 + AND ID NOT IN ('{$excludedPosts}')";
396 404
397 405 if ('readable' === $perm
398 406 && $this->wordpress->isUserLoggedIn() === true
399 407 && $this->wordpress->currentUserCan(
@@ -410,8 +418,13 @@
410 418 return $query;
411 419 }
412 420
413 421 /**
422 + * Function for the wp_count_posts filter.
423 + * @param stdClass $counts
424 + * @param string $type
425 + * @param string $perm
426 + * @return stdClass
414 427 * @throws UserGroupTypeException
415 428 */
416 429 public function showPostCount(stdClass $counts, string $type, string $perm): stdClass
417 430 {
@@ -437,8 +450,13 @@
437 450
438 451 return $this->cachedCounts[$type];
439 452 }
440 453
454 + /**
455 + * Checks if the post comment should be completely hidden.
456 + * @param string $postType
457 + * @return bool
458 + */
441 459 private function hidePostComment(string $postType): bool
442 460 {
443 461 return $this->mainConfig->lockPostTypeComments($postType) === true
444 462 || $this->mainConfig->hidePostType($postType) === true
@@ -445,12 +463,14 @@
445 463 || $this->wordpressConfig->atAdminPanel() === true;
446 464 }
447 465
448 466 /**
467 + * The function for the comments_array filter.
449 468 * @param WP_Comment[] $comments The comments.
469 + * @return array
450 470 * @throws UserGroupTypeException
451 471 */
452 - public function showComment(array $comments = []): array
472 + public function showComment($comments = []): array
453 473 {
454 474 $showComments = [];
455 475
456 476 foreach ($comments as $comment) {
@@ -474,11 +494,15 @@
474 494 return $showComments;
475 495 }
476 496
477 497 /**
498 + * The function for the edit_post_link filter.
499 + * @param string $link The edit link.
500 + * @param integer $postId The _iId of the post.
501 + * @return string
478 502 * @throws UserGroupTypeException
479 503 */
480 - public function showEditLink(?string $link, int|string|null $postId): string
504 + public function showEditLink(string $link, int $postId): string
481 505 {
482 506 if ($this->mainConfig->hideEditLinkOnNoAccess() === true
483 507 && $this->accessHandler->checkObjectAccess(ObjectHandler::GENERAL_POST_OBJECT_TYPE, $postId, true) === false
484 508 ) {
@@ -503,7 +527,7 @@
503 527 $link .= TXT_UAM_ASSIGNED_GROUPS . ': ' . implode(', ', $escapedGroups);
504 528 }
505 529 }
506 530
507 - return (string) $link;
531 + return $link;
508 532 }
509 533 }