PluginProbe
User Access Manager / 2.2.21
User Access Manager v2.2.21
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
user-access-manager / src / Controller / Frontend / PostController.php

PostController.php in User Access Manager 2.2.21, at src/Controller/Frontend/PostController.php

534 lines 16.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 */
15
16 declare(strict_types=1);
17
18 namespace UserAccessManager\Controller\Frontend;
19
20 use stdClass;
21 use UserAccessManager\Access\AccessHandler;
22 use UserAccessManager\Config\MainConfig;
23 use UserAccessManager\Config\WordpressConfig;
24 use UserAccessManager\Database\Database;
25 use UserAccessManager\Object\ObjectHandler;
26 use UserAccessManager\User\UserHandler;
27 use UserAccessManager\UserGroup\AbstractUserGroup;
28 use UserAccessManager\UserGroup\UserGroupHandler;
29 use UserAccessManager\UserGroup\UserGroupTypeException;
30 use UserAccessManager\Util\Util;
31 use UserAccessManager\Wrapper\Php;
32 use UserAccessManager\Wrapper\Wordpress;
33 use WP_Comment;
34 use WP_Hook;
35 use WP_Post;
36 use WP_Query;
37
38 /**
39 * Class FrontendPostController
40 *
41 * @package UserAccessManager\Controller
42 */
43 class PostController extends ContentController
44 {
45 /**
46 * @var Database
47 */
48 private $database;
49
50 /**
51 * @var array
52 */
53 private $wordpressFilters = [];
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 */
73 public function __construct(
74 Php $php,
75 Wordpress $wordpress,
76 WordpressConfig $wordpressConfig,
77 MainConfig $mainConfig,
78 Database $database,
79 Util $util,
80 ObjectHandler $objectHandler,
81 UserHandler $userHandler,
82 UserGroupHandler $userGroupHandler,
83 AccessHandler $accessHandler
84 ) {
85 parent::__construct(
86 $php,
87 $wordpress,
88 $wordpressConfig,
89 $mainConfig,
90 $util,
91 $objectHandler,
92 $userHandler,
93 $userGroupHandler,
94 $accessHandler
95 );
96 $this->database = $database;
97 }
98
99 /**
100 * Return the wordpress filters.
101 * @return array
102 */
103 public function getWordpressFilters(): array
104 {
105 return $this->wordpressFilters;
106 }
107
108 /**
109 * Returns true if the filters are suppressed.
110 * @param WP_Query $wpQuery
111 * @return bool
112 */
113 private function filtersSuppressed(WP_Query $wpQuery): bool
114 {
115 return isset($wpQuery->query_vars['suppress_filters']) === true
116 && $wpQuery->query_vars['suppress_filters'] === true;
117 }
118
119 /**
120 * Manipulates the wordpress query object to filter content.
121 * @param WP_Query $wpQuery The wordpress query object.
122 * @throws UserGroupTypeException
123 */
124 public function parseQuery(WP_Query $wpQuery)
125 {
126 if ($this->filtersSuppressed($wpQuery) === true) {
127 $excludedPosts = $this->accessHandler->getExcludedPosts();
128
129 if ($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)
135 );
136 }
137 }
138 }
139
140 /**
141 * Extracts the user access manager filters and returns true if it was successful.
142 * @param WP_Hook[] $filters
143 * @return bool
144 */
145 private function extractOwnFilters(array $filters): bool
146 {
147 if (isset($filters['the_posts']->callbacks[10]) === true) {
148 foreach ($filters['the_posts']->callbacks[10] as $postFilter) {
149 if (is_array($postFilter['function']) === true
150 && $postFilter['function'][0] instanceof PostController
151 && $postFilter['function'][1] === 'showPosts'
152 ) {
153 $this->wordpressFilters['the_posts'] = $filters['the_posts'];
154 $filters['the_posts']->callbacks = [10 => [$postFilter]];
155 return true;
156 }
157 }
158 }
159
160 return false;
161 }
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 */
171 public function postsPreQuery(?array $posts, WP_Query $query): ?array
172 {
173 if ($this->filtersSuppressed($query) === true) {
174 $filters = $this->wordpress->getFilters();
175
176 // Only unset filter if the user access filter is active
177 if ($this->extractOwnFilters($filters) === true) {
178 $query->query_vars['suppress_filters'] = false;
179
180 if (isset($filters['posts_results']) === true) {
181 $this->wordpressFilters['posts_results'] = $filters['posts_results'];
182 unset($filters['posts_results']);
183 }
184
185 $this->wordpress->setFilters($filters);
186 }
187 }
188
189 return $posts;
190 }
191
192 /**
193 * Restores the filters to normal.
194 */
195 private function restoreFilters()
196 {
197 if (count($this->wordpressFilters) > 0) {
198 $filters = $this->wordpress->getFilters();
199
200 foreach ($this->wordpressFilters as $filterKey => $filter) {
201 $filters[$filterKey] = $filter;
202 }
203
204 $this->wordpress->setFilters($filters);
205 $this->wordpressFilters = [];
206 }
207 }
208
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)
215 {
216 if ($post instanceof WP_post) {
217 return $post;
218 } elseif (is_int($post) === true) {
219 return $this->objectHandler->getPost($post);
220 } elseif (isset($post->ID) === true) {
221 return $this->objectHandler->getPost($post->ID);
222 }
223
224 return false;
225 }
226
227 /**
228 * Processes the post content and searches for the more tag.
229 * @param WP_Post $post
230 * @return string
231 */
232 private function processPostContent(WP_Post $post): string
233 {
234 $uamPostContent = htmlspecialchars_decode($this->mainConfig->getPostTypeContent($post->post_type));
235
236 if ($this->mainConfig->showPostTypeContentBeforeMore($post->post_type) === true
237 && preg_match('/<!--more(.*?)?-->/', $post->post_content, $matches)
238 ) {
239 $uamPostContent = explode($matches[0], $post->post_content)[0] . ' ' . $uamPostContent;
240 }
241
242 return stripslashes($uamPostContent);
243 }
244
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
249 * @throws UserGroupTypeException
250 */
251 private function processPost(WP_Post $post): ?WP_Post
252 {
253 $post->post_title .= $this->adminOutput((string) $post->post_type, $post->ID);
254
255 if ($this->accessHandler->checkObjectAccess($post->post_type, $post->ID) === false) {
256 if ($this->removePostFromList($post->post_type) === true) {
257 return null;
258 }
259
260 $post->post_content = $this->processPostContent($post);
261
262 if ($this->mainConfig->hidePostTypeTitle($post->post_type) === true) {
263 $post->post_title = $this->mainConfig->getPostTypeTitle($post->post_type);
264 }
265
266 if ($this->mainConfig->lockPostTypeComments($post->post_type) === true) {
267 $post->comment_status = 'close';
268 }
269 }
270
271 return $post;
272 }
273
274 /**
275 * Filters the raw posts.
276 * @param array $rawPosts
277 * @return array
278 * @throws UserGroupTypeException
279 */
280 private function filterRawPosts(array $rawPosts): array
281 {
282 $filteredPosts = [];
283
284 foreach ($rawPosts as $rawPost) {
285 $post = $this->getPost($rawPost);
286
287 if ($post !== false) {
288 $post = $this->processPost($post);
289
290 if ($post !== null) {
291 $filteredPosts[] = $post;
292 }
293 } else {
294 $filteredPosts[] = $rawPost;
295 }
296 }
297
298 return $filteredPosts;
299 }
300
301 /**
302 * The function for the the_posts filter.
303 * @param null|array $showPosts The posts.
304 * @return array
305 * @throws UserGroupTypeException
306 */
307 public function showPosts(?array $showPosts = []): ?array
308 {
309 if ($this->wordpress->isFeed() === false || $this->mainConfig->protectFeed() === true) {
310 $showPosts = $this->filterRawPosts((array) $showPosts);
311 }
312
313 $this->restoreFilters();
314
315 return $showPosts;
316 }
317
318 /**
319 * The function for the get_pages filter.
320 * @param WP_Post[] $rawPages The pages.
321 * @return array
322 * @throws UserGroupTypeException
323 */
324 public function showPages($rawPages = []): array
325 {
326 return $this->filterRawPosts((array) $rawPages);
327 }
328
329 /**
330 * Checks the access of the attached file.
331 * @param string $file
332 * @param int|string $attachmentId
333 * @return string|false
334 * @throws UserGroupTypeException
335 */
336 public function getAttachedFile(string $file, $attachmentId)
337 {
338 $isImage = (bool) preg_match('/(?i)\.(jpg|jpeg|jpe|png|gif)$/', $file);
339
340 if ($isImage === false && $this->mainConfig->lockFile() === true) {
341 $hasAccess = $this->accessHandler->checkObjectAccess(ObjectHandler::ATTACHMENT_OBJECT_TYPE, $attachmentId);
342 return ($hasAccess === true) ? $file : false;
343 }
344
345 return $file;
346 }
347
348 /**
349 * Adds the excluded posts filter to the given query.
350 * @param string $query
351 * @param string $table
352 * @return string
353 * @throws UserGroupTypeException
354 */
355 private function addQueryExcludedPostFilter(string $query, string $table): string
356 {
357 $excludedPosts = $this->accessHandler->getExcludedPosts();
358
359 if ($excludedPosts !== []) {
360 $excludedPostsStr = implode(', ', $excludedPosts);
361 $query .= " AND {$table}.ID NOT IN ($excludedPostsStr) ";
362 }
363
364 return $query;
365 }
366
367 /**
368 * The function for the posts_where_paged filter.
369 * @param string $query The where sql statement.
370 * @return string
371 * @throws UserGroupTypeException
372 */
373 public function showPostSql(string $query): string
374 {
375 return $this->addQueryExcludedPostFilter($query, $this->database->getPostsTable());
376 }
377
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
383 * @throws UserGroupTypeException
384 */
385 public function showNextPreviousPost(string $query): string
386 {
387 return $this->addQueryExcludedPostFilter($query, 'p');
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 */
397 private function getPostCountQuery(array $excludedPosts, string $type, string $perm): string
398 {
399 $excludedPosts = implode('\', \'', $excludedPosts);
400 $query = "SELECT post_status, COUNT(*) AS num_posts
401 FROM {$this->database->getPostsTable()}
402 WHERE post_type = %s
403 AND ID NOT IN ('{$excludedPosts}')";
404
405 if ('readable' === $perm
406 && $this->wordpress->isUserLoggedIn() === true
407 && $this->wordpress->currentUserCan(
408 $this->wordpress->getPostTypeObject($type)->cap->read_private_posts
409 ) === false
410 ) {
411 $query .= $this->database->prepare(
412 ' AND (post_status != \'private\' OR (post_author = %d AND post_status = \'private\'))',
413 $this->wordpress->getCurrentUser()->ID
414 );
415 }
416
417 $query .= ' GROUP BY post_status';
418 return $query;
419 }
420
421 /**
422 * Function for the wp_count_posts filter.
423 * @param stdClass $counts
424 * @param string $type
425 * @param string $perm
426 * @return stdClass
427 * @throws UserGroupTypeException
428 */
429 public function showPostCount(stdClass $counts, string $type, string $perm): stdClass
430 {
431 if (isset($this->cachedCounts[$type]) === false) {
432 $excludedPosts = $this->accessHandler->getExcludedPosts();
433
434 if ($excludedPosts !== []) {
435 $query = $this->getPostCountQuery($excludedPosts, $type, $perm);
436 $results = (array) $this->database->getResults(
437 $this->database->prepare($query, $type),
438 ARRAY_A
439 );
440
441 foreach ($results as $result) {
442 if (isset($counts->{$result['post_status']})) {
443 $counts->{$result['post_status']} = $result['num_posts'];
444 }
445 }
446 }
447
448 $this->cachedCounts[$type] = $counts;
449 }
450
451 return $this->cachedCounts[$type];
452 }
453
454 /**
455 * Checks if the post comment should be completely hidden.
456 * @param string $postType
457 * @return bool
458 */
459 private function hidePostComment(string $postType): bool
460 {
461 return $this->mainConfig->lockPostTypeComments($postType) === true
462 || $this->mainConfig->hidePostType($postType) === true
463 || $this->wordpressConfig->atAdminPanel() === true;
464 }
465
466 /**
467 * The function for the comments_array filter.
468 * @param WP_Comment[] $comments The comments.
469 * @return array
470 * @throws UserGroupTypeException
471 */
472 public function showComment($comments = []): array
473 {
474 $showComments = [];
475
476 foreach ($comments as $comment) {
477 $post = $this->objectHandler->getPost($comment->comment_post_ID);
478
479 if ($post !== false
480 && $this->accessHandler->checkObjectAccess($post->post_type, $post->ID) === false
481 ) {
482 if ($this->hidePostComment($post->post_type)) {
483 continue;
484 }
485
486 if ($this->mainConfig->hidePostTypeComments($post->post_type) === true) {
487 $comment->comment_content = $this->mainConfig->getPostTypeCommentContent($post->post_type);
488 }
489 }
490
491 $showComments[] = $comment;
492 }
493
494 return $showComments;
495 }
496
497 /**
498 * The function for the edit_post_link filter.
499 * @param null|string $link The edit link.
500 * @param int|string $postId The _iId of the post.
501 * @return string
502 * @throws UserGroupTypeException
503 */
504 public function showEditLink(?string $link, $postId): string
505 {
506 if ($this->mainConfig->hideEditLinkOnNoAccess() === true
507 && $this->accessHandler->checkObjectAccess(ObjectHandler::GENERAL_POST_OBJECT_TYPE, $postId, true) === false
508 ) {
509 $link = '';
510 }
511
512 if ($this->mainConfig->showAssignedGroups() === true) {
513 $userGroups = $this->userGroupHandler->getFilteredUserGroupsForObject(
514 ObjectHandler::GENERAL_POST_OBJECT_TYPE,
515 $postId
516 );
517
518 if (count($userGroups) > 0) {
519 $escapedGroups = array_map(
520 function (AbstractUserGroup $group) {
521 return htmlentities($group->getName());
522 },
523 $userGroups
524 );
525
526 $link .= $link !== '' ? ' | ' : ' ';
527 $link .= TXT_UAM_ASSIGNED_GROUPS . ': ' . implode(', ', $escapedGroups);
528 }
529 }
530
531 return (string) $link;
532 }
533 }
534