PluginProbe
ReviewX – Multi-Criteria Reviews for WooCommerce with Google Reviews & Schema / trunk
ReviewX – Multi-Criteria Reviews for WooCommerce with Google Reviews & Schema vtrunk
2.5.1 2.5.0 2.4.1 2.4.0 2.3.11 2.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.10 1.1.11 1.1.12 1.1.13 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 All 143 releases
reviewx / app / Rest / Controllers / ReviewController.php

ReviewController.php in ReviewX – Multi-Criteria Reviews for WooCommerce with Google Reviews & Schema trunk, at app/Rest/Controllers/ReviewController.php

621 lines 23.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace ReviewX\Rest\Controllers;
4
5 \defined("ABSPATH") || exit;
6 use Exception;
7 use Throwable;
8 use ReviewX\Services\ReviewDuplicateService;
9 use ReviewX\Services\ReviewService;
10 use ReviewX\Services\SaasReviewApplyService;
11 use ReviewX\Utilities\Helper;
12 use ReviewX\Services\CacheServices;
13 use ReviewX\WPDrill\Contracts\InvokableContract;
14 use ReviewX\WPDrill\Response;
15 class ReviewController implements InvokableContract
16 {
17 protected ReviewService $reviewService;
18 protected CacheServices $cacheServices;
19 protected ReviewDuplicateService $reviewDuplicateService;
20 public function __construct()
21 {
22 $this->reviewService = new ReviewService();
23 $this->cacheServices = new CacheServices();
24 $this->reviewDuplicateService = new ReviewDuplicateService();
25 }
26 /**
27 * @return void
28 */
29 public function __invoke()
30 {
31 }
32 private function refreshPendingReviewSummary() : void
33 {
34 $this->cacheServices->refreshPendingReviewNoticeSummary();
35 }
36 /**
37 * Apply a review mutation that originated in the SaaS dashboard (SaaS -> WP direction).
38 *
39 * WordPress is what the bulk data sync reads from, so a change made only in SaaS used to
40 * be reverted by the next sync. SaaS now pushes each mutation here. Authenticated by
41 * AuthSaasMiddleware; deliberately never calls back to SaaS.
42 *
43 * @param $request
44 * @return Response
45 */
46 public function applyFromSaas($request)
47 {
48 try {
49 $result = (new SaasReviewApplyService())->apply($request->get_params());
50 $this->cacheServices->removeCache();
51 $this->refreshPendingReviewSummary();
52 return Helper::rest($result)->success('Review changes applied');
53 } catch (Throwable $e) {
54 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review apply failed', $e->getCode());
55 }
56 }
57 /**
58 * @return Response
59 */
60 public function index($request)
61 {
62 $aggregation = \get_transient('rvx_admin_aggregation');
63 if (empty($request->get_params()) && $aggregation) {
64 $response = ['aggregations' => $aggregation['aggregations'], 'count' => $aggregation['count'], 'reviews' => $aggregation['reviews'], 'meta' => $aggregation['meta']];
65 return Helper::rest($response)->success("Success");
66 } else {
67 $resp = $this->reviewService->getReviews($request->get_params());
68 if ($resp->getStatusCode() === Response::HTTP_OK) {
69 $data = $resp->getApiData();
70 // Fetch fresh aggregation data as SaaS products table may be stale
71 $aggResp = $this->reviewService->reviewAggregation(['isVisible' => 'published']);
72 if ($aggResp->getStatusCode() === Response::HTTP_OK) {
73 $freshAgg = $aggResp->getApiData();
74 if (isset($freshAgg['data'])) {
75 $data['data']['aggregations'] = $freshAgg['data'];
76 }
77 }
78 $this->aggregationDataStore($data);
79 return Helper::rest($data)->success("Success");
80 }
81 return Helper::getApiResponse($resp);
82 }
83 }
84 public function aggregationDataStore($data)
85 {
86 \delete_transient('rvx_admin_aggregation');
87 \set_transient('rvx_admin_aggregation', $data, 3600);
88 }
89 public function adminAllReviewSaasCall($data)
90 {
91 $resp = $this->reviewService->reviewList($data);
92 $isVisible = $data['isVisible'] ?? '';
93 if ($resp->getStatusCode() === Response::HTTP_OK) {
94 $this->storeVisibilityReview($resp->getApiData(), $isVisible);
95 }
96 return $this->enrichReviewList($resp);
97 }
98 private function enrichReviewList($resp)
99 {
100 if ($resp->getStatusCode() === Response::HTTP_OK) {
101 $data = $resp->getApiData();
102 if (isset($data['reviews']) && \is_array($data['reviews'])) {
103 foreach ($data['reviews'] as &$review) {
104 if (isset($review['wp_post_id'])) {
105 $review['post_type'] = \get_post_type($review['wp_post_id']);
106 }
107 }
108 return Helper::rest($data)->success($resp->autoParse()['message'] ?? '', $resp->getStatusCode());
109 }
110 }
111 return Helper::getApiResponse($resp);
112 }
113 public function reviewList($request)
114 {
115 try {
116 $differentReview = $this->cacheServices->makeSaaSCallDecision();
117 $this->visibilityPaginationSaasCall($request, $differentReview);
118 $isVisible = $request->get_params()['isVisible'] ?? '';
119 $transientKeys = ['published' => 'rvx_review_approve_data', 'pending' => 'rvx_review_pending_data', 'spam' => 'rvx_review_spam_data', 'trash' => 'rvx_review_trash_data'];
120 if (\array_key_exists($isVisible, $transientKeys)) {
121 $approve = \get_transient($transientKeys[$isVisible]);
122 $params = $request->get_params();
123 $filterParams = ['page', 'rating', 'date', 'reviewer', 'search', 'product', 'category', 'oldest_first', 'newest_first'];
124 if (\array_intersect_key(\array_flip($filterParams), $params)) {
125 $resp = $this->reviewService->reviewList($params);
126 return $this->enrichReviewList($resp);
127 } elseif ($approve) {
128 $response = ['count' => $approve['count'], 'reviews' => $approve['reviews'], 'meta' => $approve['meta']];
129 return Helper::rest($response)->success("Success");
130 } else {
131 $this->adminAllReviewSaasCall($params);
132 }
133 }
134 if (empty($request->get_params())) {
135 $data = \get_transient('rvx_reviews_data_list');
136 if ($data) {
137 $response = ['count' => $data['count'], 'reviews' => $data['reviews'], 'meta' => $data['meta']];
138 return Helper::rest($response)->success("Success");
139 } else {
140 $resp = $this->reviewService->reviewList($request->get_params());
141 if ($resp->getStatusCode() === Response::HTTP_OK && empty($request->get_params())) {
142 $this->reviewListStoreInDB($resp->getApiData());
143 }
144 return $this->enrichReviewList($resp);
145 }
146 } else {
147 $resp = $this->reviewService->reviewList($request->get_params());
148 return $this->enrichReviewList($resp);
149 }
150 } catch (Exception $e) {
151 // Silently handle exception for production
152 }
153 }
154 public function visibilityPaginationSaasCall($request, $differentReview)
155 {
156 if ($differentReview === \true) {
157 $this->adminAllReviewSaasCall($request->get_params());
158 }
159 }
160 public function reviewListStoreInDB($reviewData)
161 {
162 \delete_transient('rvx_reviews_data_list');
163 \set_transient('rvx_reviews_data_list', $reviewData, 3600);
164 }
165 public function storeVisibilityReview($data, $visibility)
166 {
167 if ($visibility === 'published') {
168 \delete_transient('rvx_review_approve_data');
169 \set_transient('rvx_review_approve_data', $data, 3600);
170 }
171 if ($visibility === 'pending') {
172 \delete_transient('rvx_review_pending_data');
173 \set_transient('rvx_review_pending_data', $data, 3600);
174 }
175 if ($visibility === 'spam') {
176 \delete_transient('rvx_review_spam_data');
177 \set_transient('rvx_review_spam_data', $data, 3600);
178 }
179 if ($visibility === 'trash') {
180 \delete_transient('rvx_review_trash_data');
181 \set_transient('rvx_review_trash_data', $data, 3600);
182 }
183 }
184 /**
185 * @param $request
186 * @return Response
187 */
188 public function show($request)
189 {
190 $resp = $this->reviewService->getReview($request);
191 return Helper::getApiResponse($resp);
192 }
193 /**
194 * @param $request
195 * @return Response
196 */
197 public function store($request)
198 {
199 try {
200 // Temporarily disable comment notification emails
201 \remove_action('comment_post', 'wp_notify_postauthor');
202 \add_filter('comments_notify', '__return_false');
203 $resp = $this->reviewService->createReview($request);
204 // Re-enable the comment notification emails
205 \add_action('comment_post', 'wp_notify_postauthor');
206 \remove_filter('comments_notify', '__return_false');
207 // Clear caches
208 $this->cacheServices->removeCache();
209 $postId = $request->get_param('wp_post_id');
210 if ($postId) {
211 $this->cacheServices->removeProductCache($postId);
212 }
213 $this->refreshPendingReviewSummary();
214 return Helper::getApiResponse($resp);
215 } catch (Exception $e) {
216 // Re-enable the comment notification emails in case of error
217 \add_action('comment_post', 'wp_notify_postauthor');
218 \remove_filter('comments_notify', '__return_false');
219 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Not Create', $e->getCode());
220 }
221 }
222 /**
223 * @param $request
224 * @return Response
225 */
226 public function update($request)
227 {
228 try {
229 $resp = $this->reviewService->updateReview($request);
230 if ($resp === \true) {
231 // 1. Clear site-wide generic caches
232 $this->cacheServices->removeCache();
233 // 2. Clear product-specific caches (Insight & Latest Reviews)
234 $postId = $request->get_param('wp_post_id');
235 if ($postId) {
236 \delete_transient("rvx_{$postId}_latest_reviews_insight");
237 \delete_transient("rvx_{$postId}_latest_reviews");
238 }
239 $this->refreshPendingReviewSummary();
240 return Helper::rest([])->success('Review updated successfully');
241 }
242 if ($resp === \false) {
243 return Helper::rest([])->fails('Review Update Failed');
244 }
245 if (\is_object($resp) && \method_exists($resp, 'getStatusCode') && $resp->getStatusCode() >= 200 && $resp->getStatusCode() < 300) {
246 // 1. Clear site-wide generic caches
247 $this->cacheServices->removeCache();
248 // 2. Clear product-specific caches (Insight & Latest Reviews)
249 $postId = $request->get_param('wp_post_id');
250 if ($postId) {
251 \delete_transient("rvx_{$postId}_latest_reviews_insight");
252 \delete_transient("rvx_{$postId}_latest_reviews");
253 }
254 $this->refreshPendingReviewSummary();
255 }
256 return Helper::getApiResponse($resp);
257 } catch (Throwable $e) {
258 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Update Failed', $e->getCode());
259 }
260 }
261 /**
262 * @param $request
263 * @return Response
264 */
265 public function delete($request)
266 {
267 try {
268 $resp = $this->reviewService->deleteReview($request);
269 $this->cacheServices->removeCache();
270 $this->refreshPendingReviewSummary();
271 return $resp;
272 } catch (Throwable $e) {
273 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Visibility Change', $e->getCode());
274 }
275 }
276 /**
277 * @param $request
278 * @return Response
279 */
280 public function restoreReview($request)
281 {
282 try {
283 $response = $this->reviewService->restoreReview($request);
284 $this->cacheServices->removeCache();
285 $this->refreshPendingReviewSummary();
286 return Helper::saasResponse($response);
287 } catch (Throwable $e) {
288 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Visibility Change', $e->getCode());
289 }
290 }
291 /**
292 * @param $request
293 * @return Response
294 */
295 public function verify($request)
296 {
297 try {
298 $resp = $this->reviewService->isVerify($request);
299 $this->cacheServices->removeCache();
300 return $resp;
301 } catch (Throwable $e) {
302 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Visibility Not Change', $e->getCode());
303 }
304 }
305 /**
306 * @param $request
307 * @return Response
308 */
309 public function visibility($request)
310 {
311 try {
312 $response = $this->reviewService->isvisibility($request);
313 $this->cacheServices->removeCache();
314 $this->refreshPendingReviewSummary();
315 return Helper::saasResponse($response);
316 } catch (Throwable $e) {
317 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Visibility Not Change', $e->getCode());
318 }
319 }
320 /**
321 * @param $request
322 * @return Response
323 */
324 public function updateReqEmail($request)
325 {
326 try {
327 $resp = $this->reviewService->updateReqEmail($request);
328 $this->cacheServices->removeCache();
329 return $resp;
330 } catch (Throwable $e) {
331 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Bulk Fails', $e->getCode());
332 }
333 }
334 /**
335 * @param $request
336 * @return Response
337 */
338 public function replies($request)
339 {
340 try {
341 $resp = $this->reviewService->reviewReplies($request);
342 $this->cacheServices->removeCache();
343 return $resp;
344 } catch (Throwable $e) {
345 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Reply Fails', $e->getCode());
346 }
347 }
348 /**
349 * @param $request
350 * @return Response
351 */
352 public function repliesUpdate($request)
353 {
354 try {
355 $resp = $this->reviewService->reviewRepliesUpdate($request);
356 $this->cacheServices->removeCache();
357 return Helper::rvxApi($resp)->success('Review Reply Updated');
358 } catch (Throwable $e) {
359 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Reply Updated Fails', $e->getCode());
360 }
361 }
362 /**
363 * @param $request
364 * @return Response
365 */
366 public function replyDelete($request)
367 {
368 try {
369 $resp = $this->reviewService->reviewRepliesDelete($request);
370 $this->cacheServices->removeCache();
371 return Helper::getApiResponse($resp);
372 } catch (Throwable $e) {
373 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Bulk Fails', $e->getCode());
374 }
375 }
376 /**
377 * @param $request
378 * @return Response
379 */
380 public function aiReview($request)
381 {
382 try {
383 // Temporarily disable comment notification emails
384 \remove_action('comment_post', 'wp_notify_postauthor');
385 \add_filter('comments_notify', '__return_false');
386 $resp = $this->reviewService->aiReview($request);
387 // Re-enable the comment notification emails
388 \add_action('comment_post', 'wp_notify_postauthor');
389 \remove_filter('comments_notify', '__return_false');
390 $this->refreshPendingReviewSummary();
391 return Helper::getApiResponse($resp);
392 } catch (Throwable $e) {
393 // Re-enable the comment notification emails in case of error
394 \add_action('comment_post', 'wp_notify_postauthor');
395 \remove_filter('comments_notify', '__return_false');
396 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Bulk Fails', $e->getCode());
397 }
398 }
399 /**
400 * @param $request
401 * @return Response
402 */
403 public function aiReviewCount()
404 {
405 try {
406 $resp = $this->reviewService->aiReviewCount();
407 return Helper::getApiResponse($resp);
408 } catch (Throwable $e) {
409 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Ai Review Count', $e->getCode());
410 }
411 }
412 public function aggregationMeta($request)
413 {
414 try {
415 $response = $this->reviewService->aggregationMeta($request);
416 return Helper::saasResponse($response);
417 } catch (Throwable $e) {
418 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Bulk Fails', $e->getCode());
419 }
420 }
421 /**
422 * @param $request
423 * @return Response
424 */
425 public function reviewBulkUpdate($request)
426 {
427 try {
428 $response = $this->reviewService->reviewBulkUpdate($request->get_params());
429 $this->cacheServices->removeCache();
430 $this->refreshPendingReviewSummary();
431 return Helper::saasResponse($response);
432 } catch (Throwable $e) {
433 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Bulk Fails', $e->getCode());
434 }
435 }
436 /**
437 * @param $request
438 * @return Response
439 */
440 public function reviewBulkTrash($request)
441 {
442 try {
443 $response = $this->reviewService->reviewBulkTrash($request->get_params());
444 $this->cacheServices->removeCache();
445 $this->refreshPendingReviewSummary();
446 return Helper::saasResponse($response);
447 } catch (Throwable $e) {
448 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Bulk Fails', $e->getCode());
449 }
450 }
451 /**
452 * @param $request
453 * @return Response
454 */
455 public function reviewBulkSoftDelete($request)
456 {
457 try {
458 $response = $this->reviewService->reviewBulkSoftDelete($request->get_params());
459 $this->cacheServices->removeCache();
460 $this->refreshPendingReviewSummary();
461 return Helper::saasResponse($response);
462 } catch (Throwable $e) {
463 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Bulk Delete Fails', $e->getCode());
464 }
465 }
466 public function reviewEmptyTrash($request)
467 {
468 try {
469 $response = $this->reviewService->reviewEmptyTrash($request->get_params());
470 $this->cacheServices->removeCache();
471 $this->refreshPendingReviewSummary();
472 return Helper::saasResponse($response);
473 } catch (Throwable $e) {
474 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Empty Fails', $e->getCode());
475 }
476 }
477 public function reviewEmptySpam($request)
478 {
479 try {
480 $response = $this->reviewService->reviewEmptySpam($request->get_params());
481 $this->cacheServices->removeCache();
482 $this->refreshPendingReviewSummary();
483 return Helper::saasResponse($response);
484 } catch (Throwable $e) {
485 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Spam Empty Fails', $e->getCode());
486 }
487 }
488 /**
489 * @param $request
490 * @return Response
491 */
492 public function restoreTrashItem($request)
493 {
494 //Bulk trash
495 try {
496 $response = $this->reviewService->restoreTrashItem($request->get_params());
497 $this->cacheServices->removeCache();
498 $this->refreshPendingReviewSummary();
499 return Helper::saasResponse($response);
500 } catch (Throwable $e) {
501 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Bulk Fails', $e->getCode());
502 }
503 }
504 /**
505 *
506 * @return Response
507 */
508 public function reviewAggregation($request)
509 {
510 try {
511 $resp = $this->reviewService->reviewAggregation($request->get_params());
512 // dd($resp->getApiData());
513 return Helper::getApiResponse($resp);
514 } catch (Throwable $e) {
515 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Aggregation Fails', $e->getCode());
516 }
517 }
518 /**
519 * @param $request
520 * @return Response
521 */
522 public function reviewMoveToTrash($request)
523 {
524 try {
525 $response = $this->reviewService->reviewMoveToTrash($request->get_params());
526 $this->cacheServices->removeCache();
527 $this->refreshPendingReviewSummary();
528 return Helper::saasResponse($response);
529 } catch (Throwable $e) {
530 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Review Move to trash Fails', $e->getCode());
531 }
532 }
533 /**
534 * @param $request
535 * @return Response
536 */
537 public function highlight($request)
538 {
539 try {
540 $response = $this->reviewService->highlight($request->get_params());
541 $this->cacheServices->removeCache();
542 return Helper::saasResponse($response);
543 } catch (Throwable $e) {
544 return Helper::rvxApi(['error' => $e->getMessage()])->fails(\__('Review Highlight', 'reviewx'), $e->getCode());
545 }
546 }
547 public function bulkTenReviews($request)
548 {
549 try {
550 $response = $this->reviewService->bulkTenReviews($request->get_params());
551 $this->cacheServices->removeCache();
552 return Helper::saasResponse($response);
553 } catch (Throwable $e) {
554 return Helper::rvxApi(['error' => $e->getMessage()])->fails(\__('Latest ten reviews fails', 'reviewx'), $e->getCode());
555 }
556 }
557 public function bulkActionProductMeta($request)
558 {
559 try {
560 foreach ($request->get_params() as $item) {
561 if (!Helper::arrayGet($item, 'product_wp_id')) {
562 return "No product found";
563 }
564 $reviewAndMeta = ['reviews' => Helper::arrayGet($item, 'reviews'), 'meta' => Helper::arrayGet($item, 'meta')];
565 $latest_ten_review = \json_encode($reviewAndMeta, \true);
566 \set_transient("rvx_{$item['product_wp_id']}_latest_reviews", $latest_ten_review, 604800);
567 // Expires in 7 days
568 return Helper::rest()->success("Success");
569 }
570 } catch (Exception $e) {
571 return Helper::rest($e->getMessage())->fails("Fail");
572 }
573 }
574 /**
575 *
576 * @return Response
577 */
578 public function reviewListMultiCriteria()
579 {
580 $resp = $this->reviewService->reviewListMultiCriteria();
581 return Helper::getApiResponse($resp);
582 }
583 public function duplicateReviewList()
584 {
585 $response = $this->reviewDuplicateService->getDuplicateReviewGroups();
586 return Helper::rest($response)->success(\__('Duplicate review report loaded successfully.', 'reviewx'));
587 }
588 public function scanDuplicateReviews()
589 {
590 try {
591 $response = $this->reviewDuplicateService->scanDuplicateReviewGroups();
592 return Helper::rest($response)->success(\__('Duplicate review scan completed successfully.', 'reviewx'));
593 } catch (Throwable $e) {
594 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Duplicate Review Scan Failed', $e->getCode());
595 }
596 }
597 public function removeDuplicateReviews($request)
598 {
599 try {
600 $groupKeys = $request->get_param('group_keys');
601 $response = $this->reviewDuplicateService->removeDuplicateReviews(\is_array($groupKeys) ? $groupKeys : []);
602 return Helper::rest($response)->success($response['message'] ?? \__('Duplicate reviews removed successfully.', 'reviewx'));
603 } catch (Throwable $e) {
604 return Helper::rvxApi(['error' => $e->getMessage()])->fails('Duplicate Review Removal Failed', $e->getCode());
605 }
606 }
607 /**
608 * @param $request
609 * @return Response
610 */
611 public function getSingleProductAllReviews($request)
612 {
613 try {
614 $resp = $this->reviewService->getSingleProductAllReviews($request);
615 return Helper::getApiResponse($resp);
616 } catch (Throwable $e) {
617 return Helper::rvxApi(['error' => $e->getMessage()])->fails('failed', $e->getCode());
618 }
619 }
620 }
621