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

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