PluginProbe ʕ •ᴥ•ʔ
Atarim – Visual Feedback, Review & AI Collaboration / 5.0
Atarim – Visual Feedback, Review & AI Collaboration v5.0
5.0 trunk 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 3.2.0 3.2.1 3.22 3.22.1 3.22.2 3.22.3 3.22.4 3.22.5 3.22.6 3.3.0 3.3.1 3.3.2 3.3.2.1 3.3.2.2 3.3.3 3.30 3.31 3.32 3.4 3.4.1 3.4.3 3.4.4 3.5 3.5.1 3.6 3.6.1 3.7 3.8 3.9 3.9.1 3.9.2 3.9.3 3.9.4 3.9.6 3.9.6.1 4.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.1.3 4.2 4.2.1 4.2.2 4.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.4
atarim-visual-collaboration / admin / class-avcf-settings.php
atarim-visual-collaboration / admin Last commit date
atarim-connect-screen.php 2 weeks ago class-avcf-offboarding.php 2 weeks ago class-avcf-settings.php 2 weeks ago class-avcf-upgrade-notice.php 2 weeks ago class-user-meta.php 2 weeks ago
class-avcf-settings.php
355 lines
1 <?php
2 if (!defined('ABSPATH')) {
3 exit;
4 }
5
6 class AVCF_Settings {
7 private $function;
8
9 public function __construct() {
10 $this->function = new AVCF_Functions(); // Initialize AVCF_Functions
11
12 // Register activation hook
13 register_activation_hook(AVCF_PLUGIN_DIR . 'atarim-visual-collaboration.php', [$this, 'avcf_set_activation_redirect']);
14
15 // Setting button on the plugin page
16 add_filter( 'plugin_action_links_' . AVCF_PLUGIN_BASE, [$this, 'avcf_setting_action_link']);
17
18 // Redirect on activation
19 add_action('admin_init', [$this, 'avcf_redirect_to_settings_page']);
20
21 add_action('admin_menu', [$this, 'avcf_add_settings_page']);
22 add_action('admin_enqueue_scripts', [$this, 'avcf_admin_assets']);
23
24 // First-run connect overlay, printed at body level so it covers the
25 // whole admin and escapes any transformed ancestor in the content area.
26 add_action('admin_footer', [$this, 'avcf_render_connect_overlay']);
27
28 // Activate license
29 add_action('init', [$this, 'avcf_license_activation']);
30
31 // Temporary hook to fire action for script version of the plugin
32 add_action('init', [$this, 'avcf_auto_update_settings']);
33 }
34
35 public function avcf_set_activation_redirect() {
36 add_option('avc_plugin_activation_redirect', true);
37
38 // Enable "Do it" by default on fresh activation only.
39 add_option('avc_enable_doit', '1');
40 }
41
42 public function avcf_redirect_to_settings_page() {
43 if ($this->function->avcf_get_setting_data('avc_plugin_activation_redirect', false)) {
44 delete_option('avc_plugin_activation_redirect');
45 wp_safe_redirect(admin_url('options-general.php?page=atarim-visual-collaboration'));
46 exit();
47 }
48 }
49
50 public function avcf_setting_action_link($links) {
51 $links[] = '<a href="' . esc_url(admin_url('options-general.php?page=atarim-visual-collaboration')) . '">' . __('Settings', 'atarim-visual-collaboration') . '</a>';
52 return $links;
53 }
54
55 public function avcf_license_activation() {
56 if (! isset($_GET['atarim_response'])) {
57 return;
58 }
59
60 if (
61 ! is_admin() ||
62 ! is_user_logged_in() ||
63 ! $this->function->avcf_allowed_user_role() ||
64 ! isset($_GET['page'])
65 ) {
66 wp_safe_redirect(AVCF_HOME_URL);
67 exit;
68 }
69
70 $page_raw = sanitize_text_field(wp_unslash($_GET['page']));
71 $page_decoded = base64_decode($page_raw, true);
72
73 if (false === $page_decoded) {
74 wp_safe_redirect(AVCF_HOME_URL);
75 exit;
76 }
77
78 $parsed = [];
79 parse_str('page=' . $page_decoded, $parsed);
80
81 $page_slug = isset($parsed['page']) ? $parsed['page'] : '';
82 $atarim_state = isset($parsed['atarim_state']) ? $parsed['atarim_state'] : '';
83
84 if ('atarim-visual-collaboration' !== $page_slug) {
85 wp_safe_redirect(AVCF_HOME_URL);
86 exit;
87 }
88
89 // Verify nonce / state.
90 if (empty( $atarim_state ) || ! wp_verify_nonce($atarim_state, 'avc_new_license_activation')) {
91 wp_safe_redirect(AVCF_HOME_URL);
92 exit;
93 }
94
95 $atarim_response_raw = sanitize_text_field(wp_unslash($_GET['atarim_response']));
96 if (strpos($atarim_response_raw, '%3D') !== false) {
97 $atarim_response = substr($atarim_response_raw, -1, 3);
98 } else {
99 $atarim_response = $atarim_response_raw;
100 }
101
102 $user_id = $this->function->avcf_get_user_detail('id');
103 $user_email = $this->function->avcf_get_user_detail('email');
104 $this->function->avcf_update_settings('avc_license', base64_decode(sanitize_text_field($atarim_response)));
105 $avc_site_id = sanitize_text_field(wp_unslash($_GET['site_id']));
106 $this->function->avcf_update_settings('avc_site_id', $avc_site_id);
107 $avc_secret_token = sanitize_text_field(wp_unslash($_GET['mcp_token']));
108 $this->function->avcf_update_settings('avc_atarim_secret_token', $avc_secret_token);
109 $this->function->avcf_update_settings('avc_initial_setup_complete', 'yes');
110 $this->function->avcf_update_settings('avc_collab_active', 'yes');
111 update_user_meta($user_id, 'avc_user_type', 'webmaster', false);
112 $this->function->avcf_update_settings('avc_website_developer', $user_email);
113 $this->function->avcf_get_whitelabel();
114 wp_safe_redirect(AVCF_HOME_URL);
115 exit();
116 }
117
118 public function avcf_auto_update_settings() {
119 $isOldPluginActivated = $this->function->avcf_get_setting_data('wpf_initial_setup_complete');
120 $isNewPluginActivated = $this->function->avcf_get_setting_data('avc_initial_setup_complete');
121 if($isOldPluginActivated === 'yes' && $isNewPluginActivated === 'yes') {
122 return;
123 }
124
125 $this->function->avcf_update_site_data();
126 }
127 public function avcf_add_settings_page() {
128 add_options_page(
129 __('Atarim Visual Collaboration', 'atarim-visual-collaboration'),
130 __('Collaborate', 'atarim-visual-collaboration'),
131 'manage_options',
132 'atarim-visual-collaboration',
133 [$this, 'render_settings_page']
134 );
135 }
136
137 public function render_settings_page() {
138 echo '<div id="avc-settings-root"></div>'; // React app will render here
139 }
140
141 public function avcf_render_connect_overlay() {
142 $screen = get_current_screen();
143 if ( ! $screen || $screen->id !== 'settings_page_atarim-visual-collaboration' ) {
144 return;
145 }
146
147 // First-run only: avc_initial_setup_complete is set to 'yes' at connect
148 // success and survives disconnect, so the overlay shows until the first
149 // successful connection and never again (existing connected sites never
150 // see it).
151 if ( 'yes' === $this->function->avcf_get_setting_data('avc_initial_setup_complete') ) {
152 return;
153 }
154
155 require_once AVCF_PLUGIN_DIR . 'admin/atarim-connect-screen.php';
156 if ( function_exists('atarim_connect_screen_render') ) {
157 atarim_connect_screen_render();
158 }
159 }
160
161 public function avcf_admin_assets() {
162 $screen = get_current_screen();
163 if ($screen->id === 'settings_page_atarim-visual-collaboration') {
164 wp_enqueue_style('wp-components', includes_url('css/dist/components/style.min.css'), [], '1.0.0');
165 wp_enqueue_style('acv-setting-style', AVCF_PLUGIN_URL . 'assets/css/settings.css', false, AVCF_VERSION);
166
167 // Connect-overlay styles: only load for first-time (never-connected)
168 // users, matching when the overlay itself is rendered.
169 if ('yes' !== $this->function->avcf_get_setting_data('avc_initial_setup_complete')) {
170 wp_enqueue_style('avc-connect-screen-style', AVCF_PLUGIN_URL . 'assets/css/atarim-connect-screen.css', [], AVCF_VERSION);
171 }
172 wp_enqueue_script('avc-settings-script', AVCF_PLUGIN_URL . 'assets/build/index.js', [], '1.0.0', true);
173
174 wp_register_script('acv-setup-script', AVCF_PLUGIN_URL . 'assets/js/admin.js', false, AVCF_VERSION);
175 wp_enqueue_script('acv-setup-script');
176
177 $selected_roles = $this->function->avcf_get_setting_data('avc_selected_role', ['administrator', 'editor']);
178 $users = get_users(['role__in' => $selected_roles]);
179 $isCollabActive = $this->function->avcf_get_setting_data('avc_collab_active', 'no');
180 $atarim_state = wp_create_nonce( 'avc_new_license_activation' );
181 $page_redirect = 'atarim-visual-collaboration&atarim_state=' . $atarim_state;
182 $activationUrl = AVCF_HOME_URL . '/?activation_callback=' . base64_encode(AVCF_SITE_URL)
183 . '&page_redirect=' . base64_encode($page_redirect)
184 . '&site_url=' . base64_encode(AVCF_HOME_URL)
185 . '&collab=true';
186
187 global $wp_roles;
188 $available_roles = [];
189 if (!empty($wp_roles->roles)) {
190 foreach ($wp_roles->roles as $role_key => $role) {
191 $available_roles[] = [
192 'label' => $role['name'],
193 'value' => $role_key,
194 ];
195 }
196 }
197
198 $crm_api_url = AVCF_CRM_API;
199 $app_url = AVCF_APP_SITE_URL;
200 $registerUrl = $app_url . '/register';
201 $pluginVersion = AVCF_VERSION;
202
203 wp_localize_script('avc-settings-script', 'avcSettings', [
204 'ajaxurl' => admin_url('admin-ajax.php'),
205 'avc_nonce' => wp_create_nonce('avc-script-nonce'),
206 'isCollabActive' => $isCollabActive,
207 'activationUrl' => $activationUrl,
208 'avc_collab_link' => AVCF_HOME_URL . '/?collab=true',
209 'pluginVersion' => $pluginVersion,
210 'notice' => [
211 'enabled' => true,
212 'showForVersions' => ['4.3'],
213 'title' => 'New: AI Collaboration Is Now Built In',
214 'descriptionHtml' => '<p>We’ve rebuilt the plugin for speed and smarter collaboration - now with your own AI teammates. Get clearer feedback, fewer revisions, and real-time support from agents trained on millions of creative reviews.</p><p>Whether you’re solo or scaling, it’s like having a full QA, UX, and content team in your back pocket.</p> <a href="https://atarim.io/help/atarim-ai/atarim-ai-workflow/" target="_blank" rel="noopener noreferrer"><button class="components-button is-primary"><span class="dashicons dashicons-video-alt3" style="margin-right: 4px;"></span>See It In Action</button></a>',
215 ],
216 'settings' => [
217 'avc_selected_role' => $selected_roles,
218 'avc_website_developer' => $this->function->avcf_get_setting_data('avc_website_developer'),
219 'avc_enable_doit' => (bool) $this->function->avcf_get_setting_data('avc_enable_doit'),
220 ],
221 'users' => array_map(function ($user) {
222 return [
223 'display_name' => $user->display_name,
224 'user_email' => $user->user_email,
225 ];
226 }, $users),
227 'availableRoles' => $available_roles,
228 'logoUrl' => AVCF_PLUGIN_URL . '/images/logo.svg',
229 'i18n' => [
230 'connect' => __('Connect with Atarim', 'atarim-visual-collaboration'),
231 'disconnect' => __('Disconnect from Dashboard', 'atarim-visual-collaboration'),
232 'settings' => __('Project Settings', 'atarim-visual-collaboration'),
233 'connectHeading' => __('Connect this Site to your Atarim Workspace', 'atarim-visual-collaboration'),
234 'connectDescription' => __('Speed up feedback, reduce back & fourth and get AI suggestions right inside your site - No more guesswork or endless revisions.', 'atarim-visual-collaboration'),
235 'connectCta' => sprintf(
236 __('Don’t have an account? <a href="%s" target="_blank">Create one for free</a>', 'atarim-visual-collaboration'),
237 esc_url($registerUrl)
238 ),
239 'connected' => __('This website is connected to your dashboard.', 'atarim-visual-collaboration'),
240 'subheader' => sprintf(
241 __('Manage QA, feedback and tasks directly in your <a href="%s" target="_blank">Atarim dashboard</a>', 'atarim-visual-collaboration'),
242 esc_url($app_url)
243 ),
244 'whoCan' => __('Who can collaborate', 'atarim-visual-collaboration'),
245 'whoCanTooltip' => __('Only these user roles are going to see the colalboration interface, unless Guest Mode is switched on.', 'atarim-visual-collaboration'),
246 'howTo' => __('How to collaborate', 'atarim-visual-collaboration'),
247 'howToTooltip' => __('Click the “Share” button when inside the collaboration interface or click the button below to explore all options.', 'atarim-visual-collaboration'),
248 'howToText1' => __('<b>Copy and share a quick link</b> with your clients or colleague. OR..', 'atarim-visual-collaboration'),
249 'howToText2' => __('<b>Add <code>?collab=true</code> to any link</b> on the website. OR..', 'atarim-visual-collaboration'),
250 'howToText3' => __('<b>Turn on Guest mode to show to all</b>, via "Manage Access" tab.', 'atarim-visual-collaboration'),
251 'sharingOptions' => __('Explore Sharing Options', 'atarim-visual-collaboration'),
252 'autoLoginAs' => __('1 click login from Atarim as', 'atarim-visual-collaboration'),
253 'autoLoginAsTooltip' => __('No more sharing passwords within the team. 1 click to login AND take you to any task across your fleet of websites.', 'atarim-visual-collaboration'),
254 'enableAutoLogin' => __('Enable Auto Login', 'atarim-visual-collaboration'),
255 'saveButton' => __('Save & Apply', 'atarim-visual-collaboration'),
256 'selectUserPlaceholder' => __('-- Select a user --', 'atarim-visual-collaboration'),
257 'enableDoit' => __('Enable "<b>Do it</b>" via Atarim AI', 'atarim-visual-collaboration'),
258 'enableDoitTooltip' => __('Click to execute the feedback with 1 click. “Do it” is not visible to clients & guests. We save a backup in case the AI makes mistakes.', 'atarim-visual-collaboration'),
259 ]
260 ]);
261
262 wp_add_inline_script('avc-settings-script', "
263 document.addEventListener('DOMContentLoaded', function () {
264 const btns = document.querySelectorAll('.avc-trigger-activate');
265 if (!btns.length) return;
266
267 // Some buttons (the first-run modal CTA) keep their own styled
268 // label/icon; only change text on the rest.
269 function setLabel(el, text) {
270 if (!el.hasAttribute('data-keep-label')) { el.innerText = text; }
271 }
272
273 btns.forEach(function (b) {
274 setLabel(b, 'Preparing...');
275 b.style.pointerEvents = 'none';
276 });
277
278 fetch('{$crm_api_url}wp/auth')
279 .then(res => res.json())
280 .then(data => {
281 const { read_key, write_key } = data;
282
283 if (!read_key || !write_key) {
284 btns.forEach(function (b) {
285 setLabel(b, 'Connect with Atarim');
286 b.style.pointerEvents = 'auto';
287 });
288 alert('Failed to prepare activation. Please try again.');
289 return;
290 }
291
292 const activationUrl = '{$app_url}/fetching/?_from=wp_plugin&from_wp=true&write_key=' + write_key;
293
294 btns.forEach(function (b) {
295 b.href = activationUrl;
296 setLabel(b, 'Connect with Atarim');
297 b.style.pointerEvents = 'auto';
298 });
299
300 // Save read_key globally
301 window.avcReadKey = read_key;
302 })
303 .catch(err => {
304 console.error('Auth fetch failed:', err);
305 btns.forEach(function (b) {
306 setLabel(b, 'Connect with Atarim');
307 b.style.pointerEvents = 'auto';
308 });
309 alert('Could not prepare activation.');
310 });
311
312 // Attach polling on click (once) to every connect button.
313 btns.forEach(function (b) {
314 b.addEventListener('click', function () {
315 if (!window.avcReadKey) return;
316
317 // Play the connecting animation in the first-run overlay (if present).
318 if (window.AtarimConnect) { window.AtarimConnect.setState('connecting'); }
319
320 btns.forEach(function (x) {
321 setLabel(x, 'Authenticating...');
322 x.style.pointerEvents = 'none';
323 });
324
325 const pollUrl = '{$crm_api_url}wp/pollForAccessToken?read_key=' + window.avcReadKey;
326 const redirectUrl = '{$activationUrl}';
327
328 const interval = setInterval(() => {
329 fetch(pollUrl, { credentials: 'include' })
330 .then(res => res.json())
331 .then(data => {
332 if (data.access_token) {
333 clearInterval(interval);
334 const url = new URL(redirectUrl);
335
336 if (data.workspace_id) {
337 url.searchParams.append('workspace_id', data.workspace_id);
338 }
339
340 // Show the connected payoff in the overlay, then load
341 // the connected settings view so the page reflects it.
342 if (window.AtarimConnect) { window.AtarimConnect.setState('connected'); }
343 setTimeout(function () { window.location.href = url.toString(); }, 2200);
344 }
345 });
346 }, 3000);
347 }, { once: true });
348 });
349 });
350 ", 'after');
351 }
352 }
353 }
354
355 new AVCF_Settings();