PluginProbe
User Access Manager / 2.3.13
User Access Manager v2.3.13
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.3.13, at src/Controller/Frontend/PostController.php

421 lines 12.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace UserAccessManager\Controller\Frontend;
6
7 use stdClass;
8 use UserAccessManager\Access\AccessHandler;
9 use UserAccessManager\Config\MainConfig;
10 use UserAccessManager\Config\WordpressConfig;
11 use UserAccessManager\Database\Database;
12 use UserAccessManager\Object\ObjectHandler;
13 use UserAccessManager\User\UserHandler;
14 use UserAccessManager\UserGroup\AbstractUserGroup;
15 use UserAccessManager\UserGroup\UserGroupHandler;
16 use UserAccessManager\UserGroup\UserGroupTypeException;
17 use UserAccessManager\Util\Util;
18 use UserAccessManager\Wrapper\Php;
19 use UserAccessManager\Wrapper\Wordpress;
20 use WeakMap;
21 use WP_Comment;
22 use WP_Hook;
23 use WP_Post;
24 use WP_Query;
25
26 class PostController extends ContentController
27 {
28 private array $wordpressFilters = [];
29 private stdClass|array|null $cachedCounts = [];
30
31 private WeakMap $posts;
32
33 public function __construct(
34 Php $php,
35 Wordpress $wordpress,
36 WordpressConfig $wordpressConfig,
37 MainConfig $mainConfig,
38 Util $util,
39 ObjectHandler $objectHandler,
40 UserHandler $userHandler,
41 UserGroupHandler $userGroupHandler,
42 AccessHandler $accessHandler,
43 private Database $database
44 ) {
45 parent::__construct(
46 $php,
47 $wordpress,
48 $wordpressConfig,
49 $mainConfig,
50 $util,
51 $objectHandler,
52 $userHandler,
53 $userGroupHandler,
54 $accessHandler
55 );
56
57 $this->posts = new WeakMap();
58 }
59
60 public function getWordpressFilters(): array
61 {
62 return $this->wordpressFilters;
63 }
64
65 private function filtersSuppressed(WP_Query $wpQuery): bool
66 {
67 return isset($wpQuery->query_vars['suppress_filters']) === true
68 && $wpQuery->query_vars['suppress_filters'] === true;
69 }
70
71 /**
72 * @throws UserGroupTypeException
73 */
74 public function parseQuery(WP_Query $wpQuery): void
75 {
76 if ($this->filtersSuppressed($wpQuery) === true) {
77 $excludedPosts = $this->accessHandler->getExcludedPosts();
78
79 if ($excludedPosts !== []) {
80 $postsNotIn = (isset($wpQuery->query_vars['post__not_in']) === true) ?
81 $wpQuery->query_vars['post__not_in'] : [];
82
83 $wpQuery->query_vars['post__not_in'] = array_unique(
84 array_merge($postsNotIn, $excludedPosts)
85 );
86 }
87 }
88 }
89
90 /**
91 * @param WP_Hook[] $filters
92 */
93 private function extractOwnFilters(array $filters): bool
94 {
95 if (isset($filters['the_posts']->callbacks[10]) === true) {
96 foreach ($filters['the_posts']->callbacks[10] as $postFilter) {
97 if (is_array($postFilter['function']) === true
98 && $postFilter['function'][0] instanceof PostController
99 && $postFilter['function'][1] === 'showPosts'
100 ) {
101 $this->wordpressFilters['the_posts'] = $filters['the_posts'];
102 $filters['the_posts']->callbacks = [10 => [$postFilter]];
103 return true;
104 }
105 }
106 }
107
108 return false;
109 }
110
111 public function postsPreQuery(?array $posts, WP_Query $query): ?array
112 {
113 if ($this->filtersSuppressed($query) === true) {
114 $filters = $this->wordpress->getFilters();
115
116 // Only unset filter if the user access filter is active
117 if ($this->extractOwnFilters($filters) === true) {
118 $query->query_vars['suppress_filters'] = false;
119
120 if (isset($filters['posts_results']) === true) {
121 $this->wordpressFilters['posts_results'] = $filters['posts_results'];
122 unset($filters['posts_results']);
123 }
124
125 $this->wordpress->setFilters($filters);
126 }
127 }
128
129 return $posts;
130 }
131
132 private function restoreFilters(): void
133 {
134 if (count($this->wordpressFilters) > 0) {
135 $filters = $this->wordpress->getFilters();
136
137 foreach ($this->wordpressFilters as $filterKey => $filter) {
138 $filters[$filterKey] = $filter;
139 }
140
141 $this->wordpress->setFilters($filters);
142 $this->wordpressFilters = [];
143 }
144 }
145
146 private function getPost(mixed $post): bool|WP_Post
147 {
148 if ($post instanceof WP_post) {
149 return $post;
150 } elseif (is_int($post) === true) {
151 return $this->objectHandler->getPost($post);
152 } elseif (isset($post->ID) === true) {
153 return $this->objectHandler->getPost($post->ID);
154 }
155
156 return false;
157 }
158
159 private function processPostContent(WP_Post $post): string
160 {
161 $uamPostContent = htmlspecialchars_decode($this->mainConfig->getPostTypeContent($post->post_type));
162
163 if ($this->mainConfig->showPostTypeContentBeforeMore($post->post_type) === true
164 && preg_match('/<!--more(.*?)?-->/', $post->post_content, $matches)
165 ) {
166 $uamPostContent = explode($matches[0], $post->post_content)[0] . ' ' . $uamPostContent;
167 }
168
169 return stripslashes($uamPostContent);
170 }
171
172 /**
173 * @throws UserGroupTypeException
174 */
175 private function processPost(WP_Post $post): WP_Post|bool
176 {
177 $post->post_title .= $this->adminOutput($post->post_type, $post->ID);
178
179 if ($this->accessHandler->checkObjectAccess($post->post_type, $post->ID) === false) {
180 if ($this->removePostFromList($post->post_type) === true) {
181 return false;
182 }
183
184 $post->post_content = $this->processPostContent($post);
185
186 if ($this->mainConfig->hidePostTypeTitle($post->post_type) === true) {
187 $post->post_title = $this->mainConfig->getPostTypeTitle($post->post_type);
188 }
189
190 if ($this->mainConfig->lockPostTypeComments($post->post_type) === true) {
191 $post->comment_status = 'close';
192 }
193 }
194
195 return $post;
196 }
197
198 /**
199 * @throws UserGroupTypeException
200 */
201 private function getProcessedPost(WP_Post $post): ?WP_Post
202 {
203 $post = $this->posts[$post] ??= $this->processPost($post);
204 return $post === false ? null : $post;
205 }
206
207 /**
208 * @throws UserGroupTypeException
209 */
210 private function filterRawPosts(array $rawPosts): array
211 {
212 $filteredPosts = [];
213
214 foreach ($rawPosts as $rawPost) {
215 $post = $this->getPost($rawPost);
216
217 if ($post !== false) {
218 $post = $this->getProcessedPost($post);
219
220 if ($post !== null) {
221 $filteredPosts[] = $post;
222 }
223 } else {
224 $filteredPosts[] = $rawPost;
225 }
226 }
227
228 return $filteredPosts;
229 }
230
231 /**
232 * @throws UserGroupTypeException
233 */
234 public function showPosts(?array $showPosts = []): ?array
235 {
236 if ($this->wordpress->isFeed() === false || $this->mainConfig->protectFeed() === true) {
237 $showPosts = $this->filterRawPosts((array) $showPosts);
238 }
239
240 $this->restoreFilters();
241
242 return $showPosts;
243 }
244
245 /**
246 * @param WP_Post[] $rawPages The pages.
247 * @throws UserGroupTypeException
248 */
249 public function showPages(array $rawPages = []): array
250 {
251 return $this->filterRawPosts($rawPages);
252 }
253
254 /**
255 * @throws UserGroupTypeException
256 */
257 public function getAttachedFile(string $file, int|string|null $attachmentId): bool|string
258 {
259 $isImage = (bool) preg_match('/(?i)\.(jpg|jpeg|jpe|png|gif)$/', $file);
260
261 if ($isImage === false && $this->mainConfig->lockFile() === true) {
262 $hasAccess = $this->accessHandler->checkObjectAccess(ObjectHandler::ATTACHMENT_OBJECT_TYPE, $attachmentId);
263 return ($hasAccess === true) ? $file : false;
264 }
265
266 return $file;
267 }
268
269 /**
270 * @throws UserGroupTypeException
271 */
272 private function addQueryExcludedPostFilter(string $query, string $table): string
273 {
274 $excludedPosts = $this->accessHandler->getExcludedPosts();
275
276 if ($excludedPosts !== []) {
277 $excludedPostsStr = implode(', ', array_map('intval', $excludedPosts));
278 $query .= " AND $table.ID NOT IN ($excludedPostsStr) ";
279 }
280
281 return $query;
282 }
283
284 /**
285 * @throws UserGroupTypeException
286 */
287 public function showPostSql(string $query): string
288 {
289 return $this->addQueryExcludedPostFilter($query, $this->database->getPostsTable());
290 }
291
292 /**
293 * @throws UserGroupTypeException
294 */
295 public function showNextPreviousPost(string $query): string
296 {
297 return $this->addQueryExcludedPostFilter($query, 'p');
298 }
299
300 private function getPostCountQuery(array $excludedPosts, string $type, string $perm): string
301 {
302 $excludedPosts = implode(', ', array_map('intval', $excludedPosts));
303 $query = "SELECT post_status, COUNT(*) AS num_posts
304 FROM {$this->database->getPostsTable()}
305 WHERE post_type = %s
306 AND ID NOT IN ($excludedPosts)";
307
308 if ('readable' === $perm
309 && $this->wordpress->isUserLoggedIn() === true
310 && $this->wordpress->currentUserCan(
311 $this->wordpress->getPostTypeObject($type)->cap->read_private_posts
312 ) === false
313 ) {
314 $query .= $this->database->prepare(
315 ' AND (post_status != \'private\' OR (post_author = %d AND post_status = \'private\'))',
316 $this->wordpress->getCurrentUser()->ID
317 );
318 }
319
320 $query .= ' GROUP BY post_status';
321 return $query;
322 }
323
324 /**
325 * @throws UserGroupTypeException
326 */
327 public function showPostCount(stdClass $counts, string $type, string $perm): stdClass
328 {
329 if (isset($this->cachedCounts[$type]) === false) {
330 $excludedPosts = $this->accessHandler->getExcludedPosts();
331
332 if ($excludedPosts !== []) {
333 $query = $this->getPostCountQuery($excludedPosts, $type, $perm);
334 $results = (array) $this->database->getResults(
335 $this->database->prepare($query, $type),
336 ARRAY_A
337 );
338
339 foreach ($results as $result) {
340 if (isset($counts->{$result['post_status']})) {
341 $counts->{$result['post_status']} = $result['num_posts'];
342 }
343 }
344 }
345
346 $this->cachedCounts[$type] = $counts;
347 }
348
349 return $this->cachedCounts[$type];
350 }
351
352 private function hidePostComment(string $postType): bool
353 {
354 return $this->mainConfig->lockPostTypeComments($postType) === true
355 || $this->mainConfig->hidePostType($postType) === true
356 || $this->wordpressConfig->atAdminPanel() === true;
357 }
358
359 /**
360 * @param WP_Comment[] $comments The comments.
361 * @throws UserGroupTypeException
362 */
363 public function showComment(array $comments = []): array
364 {
365 $showComments = [];
366
367 foreach ($comments as $comment) {
368 $post = $this->objectHandler->getPost($comment->comment_post_ID);
369
370 if ($post !== false
371 && $this->accessHandler->checkObjectAccess($post->post_type, $post->ID) === false
372 ) {
373 if ($this->hidePostComment($post->post_type)) {
374 continue;
375 }
376
377 if ($this->mainConfig->hidePostTypeComments($post->post_type) === true) {
378 $comment->comment_content = $this->mainConfig->getPostTypeCommentContent($post->post_type);
379 }
380 }
381
382 $showComments[] = $comment;
383 }
384
385 return $showComments;
386 }
387
388 /**
389 * @throws UserGroupTypeException
390 */
391 public function showEditLink(?string $link, int|string|null $postId): string
392 {
393 if ($this->mainConfig->hideEditLinkOnNoAccess() === true
394 && $this->accessHandler->checkObjectAccess(ObjectHandler::GENERAL_POST_OBJECT_TYPE, $postId, true) === false
395 ) {
396 $link = '';
397 }
398
399 if ($this->mainConfig->showAssignedGroups() === true) {
400 $userGroups = $this->userGroupHandler->getFilteredUserGroupsForObject(
401 ObjectHandler::GENERAL_POST_OBJECT_TYPE,
402 $postId
403 );
404
405 if (count($userGroups) > 0) {
406 $escapedGroups = array_map(
407 function (AbstractUserGroup $group) {
408 return htmlentities($group->getName());
409 },
410 $userGroups
411 );
412
413 $link .= $link !== '' ? ' | ' : ' ';
414 $link .= TXT_UAM_ASSIGNED_GROUPS . ': ' . implode(', ', $escapedGroups);
415 }
416 }
417
418 return (string) $link;
419 }
420 }
421