PluginProbe
404 Solution / trunk
404 Solution vtrunk
4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.0 4.1.19 4.1.18 4.1.17 4.1.16 4.1.15 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.1.7 4.1.6 4.1.5 4.1.4 4.1.3 trunk 2.30.0 All 109 releases
404-solution / includes / repositories / ReviewStateRepository.php

ReviewStateRepository.php in 404 Solution trunk, at includes/repositories/ReviewStateRepository.php

147 lines 5.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) {
4 exit;
5 }
6
7 /**
8 * Data-access layer for the review-request flow.
9 *
10 * Owns every read and write of the per-user review-solicitation state and the
11 * site-level feedback store, so the controller (ABJ_404_Solution_ReviewFeedback)
12 * never touches user-meta / option storage directly. The meta keys and their
13 * stored values (the step-machine markers) are encapsulated here; callers speak
14 * in terms of state transitions, not storage strings.
15 *
16 * Storage map:
17 * user meta abj404_review_step -> '' | STEP_REVIEW_LINK | STEP_FEEDBACK
18 * user meta abj404_review_remind_later -> int unix-seconds "snooze until"
19 * user meta abj404_review_dismissed -> '' | DISMISSED_PERMANENT
20 * option abj404_installed_time -> int unix-seconds first-seen
21 * option abj404_user_feedback -> array<int, array<string, mixed>>
22 *
23 * Limitations: operates on the current user (get_current_user_id()); not safe to
24 * call before WordPress has resolved the current user. All methods degrade to
25 * the empty/zero state when meta or options are missing.
26 */
27 class ABJ_404_Solution_ReviewStateRepository {
28
29 /** Step value: the satisfied user has been offered the review link. */
30 public const STEP_REVIEW_LINK = 'show_review_link';
31
32 /** Step value: the unsatisfied user has been offered the feedback form. */
33 public const STEP_FEEDBACK = 'show_feedback';
34
35 /** Dismissed value: the user will never be asked again. */
36 private const DISMISSED_PERMANENT = 'permanent';
37
38 private const META_STEP = 'abj404_review_step';
39 private const META_REMIND_LATER = 'abj404_review_remind_later';
40 private const META_DISMISSED = 'abj404_review_dismissed';
41 private const OPTION_INSTALLED_TIME = 'abj404_installed_time';
42 private const OPTION_FEEDBACK = 'abj404_user_feedback';
43
44 /**
45 * Advance a satisfied user to the review-link step and cancel any pending
46 * snooze. (The 'yes' response.)
47 *
48 * @return void
49 */
50 public function advanceToReviewLinkStep(): void {
51 $userId = get_current_user_id();
52 update_user_meta($userId, self::META_STEP, self::STEP_REVIEW_LINK);
53 delete_user_meta($userId, self::META_REMIND_LATER);
54 }
55
56 /**
57 * Advance an unsatisfied user to the feedback-form step and cancel any
58 * pending snooze. (The 'not_yet' response.)
59 *
60 * @return void
61 */
62 public function advanceToFeedbackStep(): void {
63 $userId = get_current_user_id();
64 update_user_meta($userId, self::META_STEP, self::STEP_FEEDBACK);
65 delete_user_meta($userId, self::META_REMIND_LATER);
66 }
67
68 /**
69 * Snooze the review request until the given unix timestamp and clear the
70 * current step. (The 'ask_later' and 'close_x' responses.)
71 *
72 * @param int $timestamp unix-seconds to suppress the request until
73 * @return void
74 */
75 public function snoozeReminderUntil(int $timestamp): void {
76 $userId = get_current_user_id();
77 update_user_meta($userId, self::META_REMIND_LATER, $timestamp);
78 delete_user_meta($userId, self::META_STEP);
79 }
80
81 /**
82 * Permanently dismiss the review request and clear all transient state.
83 * (The 'never' response, the leaving-review click, and feedback submission.)
84 *
85 * @return void
86 */
87 public function dismissPermanently(): void {
88 $userId = get_current_user_id();
89 update_user_meta($userId, self::META_DISMISSED, self::DISMISSED_PERMANENT);
90 delete_user_meta($userId, self::META_STEP);
91 delete_user_meta($userId, self::META_REMIND_LATER);
92 }
93
94 /**
95 * Append one feedback submission to the site-level feedback store.
96 *
97 * @param array<string, mixed> $entry
98 * @return void
99 */
100 public function appendFeedbackEntry(array $entry): void {
101 $existingRaw = get_option(self::OPTION_FEEDBACK, array());
102 $existing = is_array($existingRaw) ? $existingRaw : array();
103 $existing[] = $entry;
104 update_option(self::OPTION_FEEDBACK, $existing);
105 }
106
107 /**
108 * @return string '' | self::STEP_REVIEW_LINK | self::STEP_FEEDBACK
109 */
110 public function getCurrentStep(): string {
111 $step = get_user_meta(get_current_user_id(), self::META_STEP, true);
112 return is_string($step) ? $step : '';
113 }
114
115 /**
116 * @return int unix-seconds the request is snoozed until, or 0 if not snoozed
117 */
118 public function getReminderTimestamp(): int {
119 $remindLater = get_user_meta(get_current_user_id(), self::META_REMIND_LATER, true);
120 return is_numeric($remindLater) ? (int) $remindLater : 0;
121 }
122
123 /**
124 * @return bool true if the user has permanently dismissed the request
125 */
126 public function isPermanentlyDismissed(): bool {
127 $dismissed = get_user_meta(get_current_user_id(), self::META_DISMISSED, true);
128 return $dismissed === self::DISMISSED_PERMANENT;
129 }
130
131 /**
132 * @return int first-seen unix timestamp, or 0 if unset / invalid
133 */
134 public function getInstalledTime(): int {
135 $installedTimeRaw = get_option(self::OPTION_INSTALLED_TIME);
136 return is_numeric($installedTimeRaw) ? (int) $installedTimeRaw : 0;
137 }
138
139 /**
140 * @param int $timestamp first-seen unix timestamp to persist
141 * @return void
142 */
143 public function setInstalledTime(int $timestamp): void {
144 update_option(self::OPTION_INSTALLED_TIME, $timestamp);
145 }
146 }
147