PluginProbe
WDesignKit – AI Templates, Widget Builder & MCP Workflow / 2.7.0
WDesignKit – AI Templates, Widget Builder & MCP Workflow v2.7.0
2.7.0 2.6.6 2.6.5 2.6.4 2.6.3 2.6.2 2.6.1 2.6.0 2.5.5 2.5.4 2.5.3 2.5.2 2.5.1 2.5.0 2.4.0 2.3.3 2.3.2 2.3.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 All 129 releases
wdesignkit / includes / abilities / auth / wdesignkit-login.php

wdesignkit-login.php in WDesignKit – AI Templates, Widget Builder & MCP Workflow 2.7.0, at includes/abilities/auth/wdesignkit-login.php

675 lines 25.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Abilities: Login, logout, sign up, and password reset for WDesignKit cloud.
4 */
5
6 declare(strict_types=1);
7
8 if (!defined('ABSPATH')) {
9 exit();
10 }
11
12 wp_register_ability('wdesignkit/login', [
13 'label' => __('Login to WDesignKit Cloud', 'wdesignkit'),
14 'description' => __(
15 'Authenticates the user against the WDesignKit cloud using email and password, and stores the session token locally. Use remember_me: true for a 90-day session; false (default) for a 1-day session.',
16 'wdesignkit',
17 ),
18 'category' => 'wdesignkit',
19 'input_schema' => [
20 'type' => 'object',
21 'properties' => [
22 'email' => [
23 'type' => 'string',
24 'description' => 'WDesignKit cloud account email address.',
25 ],
26 'password' => [
27 'type' => 'string',
28 'description' => 'WDesignKit cloud account password.',
29 ],
30 'remember_me' => [
31 'type' => 'boolean',
32 'description' => 'true = 90-day session (Remember Me). false (default) = 1-day session.',
33 ],
34 ],
35 'required' => ['email', 'password'],
36 'additionalProperties' => false,
37 ],
38 'output_schema' => [
39 'type' => 'object',
40 'properties' => [
41 'success' => ['type' => 'boolean'],
42 'message' => ['type' => 'string'],
43 'email' => ['type' => ['string', 'null']],
44 ],
45 ],
46 'execute_callback' => 'wdesignkit_mcp_login',
47 'permission_callback' => 'wdesignkit_mcp_permission_callback',
48 'meta' => [
49 'public' => true,
50 'show_in_rest' => true,
51 'mcp' => ['public' => true],
52 'annotations' => [
53 'instructions' => implode("\n", [
54 'Logs in with email and password and stores the session locally.',
55 'remember_me: true stores for 90 days; false (default) stores for 1 day.',
56 'After logging in, use wdesignkit/get-login-status to confirm the session.',
57 'All cloud operations (workspace, marketplace, upload) require a valid session.',
58 ]),
59 'readonly' => false,
60 'destructive' => false,
61 'idempotent' => false,
62 ],
63 ],
64 ]);
65
66 wp_register_ability('wdesignkit/login-api-key', [
67 'label' => __('Login to WDesignKit Cloud with API Key', 'wdesignkit'),
68 'description' => __(
69 'Authenticates the user against the WDesignKit cloud using a personal API token (instead of email and password), and stores the session locally. Useful for automation and CI workflows.',
70 'wdesignkit',
71 ),
72 'category' => 'wdesignkit',
73 'input_schema' => [
74 'type' => 'object',
75 'properties' => [
76 'api_key' => [
77 'type' => 'string',
78 'description' => 'WDesignKit personal API token / key.',
79 ],
80 ],
81 'required' => ['api_key'],
82 'additionalProperties' => false,
83 ],
84 'output_schema' => [
85 'type' => 'object',
86 'properties' => [
87 'success' => ['type' => 'boolean'],
88 'message' => ['type' => 'string'],
89 'email' => ['type' => ['string', 'null']],
90 ],
91 ],
92 'execute_callback' => 'wdesignkit_mcp_login_api_key',
93 'permission_callback' => 'wdesignkit_mcp_permission_callback',
94 'meta' => [
95 'public' => true,
96 'show_in_rest' => true,
97 'mcp' => ['public' => true],
98 'annotations' => [
99 'instructions' => implode("\n", [
100 'Logs in using a WDesignKit API token rather than email/password.',
101 'Obtain the API key from wdesignkit.com account settings.',
102 'Session is stored for 90 days on success.',
103 'Use wdesignkit/get-login-status to confirm the session afterwards.',
104 ]),
105 'readonly' => false,
106 'destructive' => false,
107 'idempotent' => false,
108 ],
109 ],
110 ]);
111
112 wp_register_ability('wdesignkit/social-login', [
113 'label' => __('Login / Sign Up to WDesignKit Cloud via Google or Facebook', 'wdesignkit'),
114 'description' => __(
115 'Completes a WDesignKit Google or Facebook OAuth login/signup using the state code produced after the user authorises in the OAuth browser popup. Covers Login with Google, Login with Facebook, Sign Up with Google, and Sign Up with Facebook — all share the same backend endpoint.',
116 'wdesignkit',
117 ),
118 'category' => 'wdesignkit',
119 'input_schema' => [
120 'type' => 'object',
121 'properties' => [
122 'state' => [
123 'type' => 'string',
124 'description' => 'The unique state ID generated before opening the OAuth popup. The server exchanges this for a token after the user authorises.',
125 ],
126 ],
127 'required' => ['state'],
128 'additionalProperties' => false,
129 ],
130 'output_schema' => [
131 'type' => 'object',
132 'properties' => [
133 'success' => ['type' => 'boolean'],
134 'message' => ['type' => 'string'],
135 'email' => ['type' => ['string', 'null']],
136 'response' => ['type' => ['object', 'array']],
137 ],
138 ],
139 'execute_callback' => 'wdesignkit_mcp_social_login',
140 'permission_callback' => 'wdesignkit_mcp_permission_callback',
141 'meta' => [
142 'public' => true,
143 'show_in_rest' => true,
144 'mcp' => ['public' => true],
145 'annotations' => [
146 'instructions' => implode("\n", [
147 'Step 2 of the Google/Facebook OAuth login or signup flow.',
148 'First call wdesignkit/get-social-login-url(provider) to get the auth_url and state (Step 1).',
149 'Open auth_url in a browser popup for the user to authorise, then call this ability with the state.',
150 'Covers: Login with Google, Login with Facebook, Sign Up with Google, Sign Up with Facebook.',
151 'On success the session is stored for 90 days.',
152 ]),
153 'readonly' => false,
154 'destructive' => false,
155 'idempotent' => false,
156 ],
157 ],
158 ]);
159
160 wp_register_ability('wdesignkit/signup', [
161 'label' => __('Sign Up for WDesignKit Cloud', 'wdesignkit'),
162 'description' => __(
163 'Creates a new WDesignKit cloud account with a full name, email address, and password, then stores the session token locally so cloud features are immediately available.',
164 'wdesignkit',
165 ),
166 'category' => 'wdesignkit',
167 'input_schema' => [
168 'type' => 'object',
169 'properties' => [
170 'fullname' => [
171 'type' => 'string',
172 'description' => 'Full name for the new account.',
173 ],
174 'email' => [
175 'type' => 'string',
176 'description' => 'Email address for the new account.',
177 ],
178 'password' => [
179 'type' => 'string',
180 'description' => 'Password for the new account.',
181 ],
182 ],
183 'required' => ['fullname', 'email', 'password'],
184 'additionalProperties' => false,
185 ],
186 'output_schema' => [
187 'type' => 'object',
188 'properties' => [
189 'success' => ['type' => 'boolean'],
190 'message' => ['type' => 'string'],
191 'email' => ['type' => ['string', 'null']],
192 ],
193 ],
194 'execute_callback' => 'wdesignkit_mcp_signup',
195 'permission_callback' => 'wdesignkit_mcp_permission_callback',
196 'meta' => [
197 'public' => true,
198 'show_in_rest' => true,
199 'mcp' => ['public' => true],
200 'annotations' => [
201 'instructions' => implode("\n", [
202 'Creates a new WDesignKit cloud account and stores the session.',
203 'If successful, the user is immediately logged in (1-day session stored).',
204 'Use wdesignkit/get-login-status to confirm the session afterwards.',
205 ]),
206 'readonly' => false,
207 'destructive' => false,
208 'idempotent' => false,
209 ],
210 ],
211 ]);
212
213 wp_register_ability('wdesignkit/forgot-password', [
214 'label' => __('WDesignKit Cloud Forgot Password', 'wdesignkit'),
215 'description' => __(
216 'Sends a password reset email to the specified WDesignKit cloud account address. This is a read-only operation — no local session is modified.',
217 'wdesignkit',
218 ),
219 'category' => 'wdesignkit',
220 'input_schema' => [
221 'type' => 'object',
222 'properties' => [
223 'email' => [
224 'type' => 'string',
225 'description' => 'Email address of the WDesignKit cloud account to reset.',
226 ],
227 ],
228 'required' => ['email'],
229 'additionalProperties' => false,
230 ],
231 'output_schema' => [
232 'type' => 'object',
233 'properties' => [
234 'success' => ['type' => 'boolean'],
235 'message' => ['type' => 'string'],
236 ],
237 ],
238 'execute_callback' => 'wdesignkit_mcp_forgot_password',
239 'permission_callback' => 'wdesignkit_mcp_permission_callback',
240 'meta' => [
241 'public' => true,
242 'show_in_rest' => true,
243 'mcp' => ['public' => true],
244 'annotations' => [
245 'instructions' => implode("\n", [
246 'Sends a password reset email to the given address.',
247 'No local session is created or modified.',
248 'After resetting, use wdesignkit/login to start a new session.',
249 ]),
250 'readonly' => true,
251 'destructive' => false,
252 'idempotent' => true,
253 ],
254 ],
255 ]);
256
257 wp_register_ability('wdesignkit/logout', [
258 'label' => __('Logout from WDesignKit Cloud', 'wdesignkit'),
259 'description' => __(
260 'Logs the currently authenticated user out of WDesignKit cloud. Deletes the local session transient, calls the cloud logout endpoint to invalidate the token, and clears the cached licence data.',
261 'wdesignkit',
262 ),
263 'category' => 'wdesignkit',
264 'input_schema' => [
265 'type' => 'object',
266 ],
267 'output_schema' => [
268 'type' => 'object',
269 'properties' => [
270 'success' => ['type' => 'boolean'],
271 'message' => ['type' => 'string'],
272 ],
273 ],
274 'execute_callback' => 'wdesignkit_mcp_logout',
275 'permission_callback' => 'wdesignkit_mcp_permission_callback',
276 'meta' => [
277 'public' => true,
278 'show_in_rest' => true,
279 'mcp' => ['public' => true],
280 'annotations' => [
281 'instructions' => implode("\n", [
282 'Logs out the current WDesignKit cloud session.',
283 'Deletes the local auth transient and calls the cloud logout endpoint.',
284 'Also clears cached licence data (wdkit_licence_data option).',
285 'Use wdesignkit/get-login-status to confirm logout.',
286 ]),
287 'readonly' => false,
288 'destructive' => false,
289 'idempotent' => true,
290 ],
291 ],
292 ]);
293
294 wp_register_ability('wdesignkit/get-social-login-url', [
295 'label' => __('Get WDesignKit Social Login URL', 'wdesignkit'),
296 'description' => __(
297 'Generates a Google or Facebook OAuth authorisation URL and a unique state token. Step 1 of social login: open the returned auth_url in a browser popup for the user to authorise, then pass the state to wdesignkit/social-login (Step 2) once the popup closes.',
298 'wdesignkit',
299 ),
300 'category' => 'wdesignkit',
301 'input_schema' => [
302 'type' => 'object',
303 'properties' => [
304 'provider' => [
305 'type' => 'string',
306 'description' => 'OAuth provider: "google" or "facebook".',
307 'enum' => ['google', 'facebook'],
308 ],
309 ],
310 'required' => ['provider'],
311 'additionalProperties' => false,
312 ],
313 'output_schema' => [
314 'type' => 'object',
315 'properties' => [
316 'success' => ['type' => 'boolean'],
317 'message' => ['type' => 'string'],
318 'provider' => ['type' => 'string'],
319 'auth_url' => ['type' => 'string'],
320 'state' => ['type' => 'string'],
321 'expires_in' => ['type' => 'integer'],
322 ],
323 ],
324 'execute_callback' => 'wdesignkit_mcp_get_social_login_url',
325 'permission_callback' => 'wdesignkit_mcp_permission_callback',
326 'meta' => [
327 'public' => true,
328 'show_in_rest' => true,
329 'mcp' => ['public' => true],
330 'annotations' => [
331 'instructions' => implode("\n", [
332 'Step 1 of the 2-step Google/Facebook OAuth login or signup flow.',
333 'Returns auth_url and state. Open auth_url in a browser popup for the user to authorise.',
334 'After the user authorises and the popup closes, pass state to wdesignkit/social-login.',
335 'The state token is valid for approximately 10 minutes (expires_in seconds).',
336 'Covers: Login with Google, Login with Facebook, Sign Up with Google, Sign Up with Facebook.',
337 ]),
338 'readonly' => true,
339 'destructive' => false,
340 'idempotent' => false,
341 ],
342 ],
343 ]);
344
345 // === Callback implementations ===
346
347 function wdesignkit_mcp_login(array $input): array {
348 if (!defined('WDKIT_SERVER_API_URL')) {
349 return ['success' => false, 'message' => 'WDesignKit plugin is not active.'];
350 }
351
352 $email = strtolower(sanitize_email((string) ($input['email'] ?? '')));
353 $password = sanitize_text_field((string) ($input['password'] ?? ''));
354 $remember_me = (bool) ($input['remember_me'] ?? false);
355
356 if ($email === '' || $password === '') {
357 return ['success' => false, 'message' => 'email and password are required.'];
358 }
359
360 $user_key = wdesignkit_cloud_session_key($email);
361
362 // Clear any existing session for this user
363 delete_transient('wdkit_auth_' . $user_key);
364
365 $response = wdesignkit_mcp_template_cloud_call('login', [
366 'user_email' => $email,
367 'password' => $password,
368 'site_url' => home_url(),
369 ], 'json');
370
371 if (empty($response['success'])) {
372 return [
373 'success' => false,
374 'message' => $response['message'] ?? $response['massage'] ?? 'Login failed. Check email and password.',
375 'email' => null,
376 ];
377 }
378
379 $token = sanitize_text_field((string) ($response['token'] ?? ''));
380
381 if ($token === '') {
382 return ['success' => false, 'message' => 'Login succeeded but no token returned.', 'email' => null];
383 }
384
385 // Resolve cloud user_id — needed for download-widget u_id auto-resolution.
386 // The login response may expose it under different keys depending on the endpoint.
387 $user_data_login = $response['user'] ?? [];
388 $cloud_user_id = (string) ($user_data_login['id'] ?? $user_data_login['user_id'] ?? $response['user_id'] ?? $response['id'] ?? '');
389
390 // Store session — 90 days for "remember me", 1 day for session-only
391 $expiry = $remember_me ? 7776000 : 86400;
392 set_transient('wdkit_auth_' . $user_key, [
393 'user_email' => $email,
394 'token' => $token,
395 'user_id' => $cloud_user_id,
396 ], $expiry);
397
398 // Point every later cloud call at THIS account. The transient is keyed off the
399 // cloud email, which rarely matches the WP user's email, so without the pointer
400 // the session can only be found by scanning wp_options.
401 wdesignkit_mcp_remember_session($user_key);
402
403 return [
404 'success' => true,
405 'message' => $response['message'] ?? 'Logged in successfully.',
406 'email' => $email,
407 ];
408 }
409
410 function wdesignkit_mcp_login_api_key(array $input): array {
411 if (!defined('WDKIT_SERVER_API_URL')) {
412 return ['success' => false, 'message' => 'WDesignKit plugin is not active.'];
413 }
414
415 $api_key = sanitize_text_field((string) ($input['api_key'] ?? ''));
416
417 if ($api_key === '') {
418 return ['success' => false, 'message' => 'api_key is required.'];
419 }
420
421 $response = wdesignkit_mcp_template_cloud_call('login/api', [
422 'token' => $api_key,
423 'site_url' => home_url(),
424 ], 'form');
425
426 if (empty($response['success'])) {
427 $message = $response['message'] ?? $response['massage'] ?? 'API key login failed.';
428 // Normalize raw HTTP-status messages ("WDesignKit cloud returned status 4xx")
429 // that leak from the shared cloud-call helper on authentication failures.
430 if (preg_match('/returned status\s+4\d\d/i', $message)) {
431 $message = 'Invalid API key. Please check your WDesignKit API token.';
432 }
433 return ['success' => false, 'message' => $message, 'email' => null];
434 }
435
436 // Response data: user->user_email
437 $user_data = $response['user'] ?? [];
438 $user_email = strtolower(sanitize_email((string) ($user_data['user_email'] ?? '')));
439 $user_key = $user_email !== '' ? wdesignkit_cloud_session_key($user_email) : '';
440
441 if ($user_key !== '') {
442 // $user_data already extracted above: $response['user'] ?? []
443 $cloud_user_id_api = (string) ($user_data['id'] ?? $user_data['user_id'] ?? $response['user_id'] ?? $response['id'] ?? '');
444 set_transient('wdkit_auth_' . $user_key, [
445 'user_email' => $user_email,
446 'token' => $api_key,
447 'user_id' => $cloud_user_id_api,
448 ], 7776000); // 90 days
449
450 wdesignkit_mcp_remember_session($user_key);
451 }
452
453 return [
454 'success' => true,
455 'message' => 'Logged in with API key successfully.',
456 'email' => $user_email ?: null,
457 ];
458 }
459
460 function wdesignkit_mcp_social_login(array $input): array {
461 if (!defined('WDKIT_SERVER_API_URL')) {
462 return ['success' => false, 'message' => 'WDesignKit plugin is not active.'];
463 }
464
465 $state = sanitize_text_field((string) ($input['state'] ?? ''));
466
467 if ($state === '') {
468 return ['success' => false, 'message' => 'state is required.'];
469 }
470
471 $response = wdesignkit_mcp_template_cloud_call('login/ip', [
472 'state' => $state,
473 'site_url' => home_url(),
474 ], 'form');
475
476 if (empty($response['success'])) {
477 return [
478 'success' => false,
479 'message' => $response['message'] ?? $response['massage'] ?? 'Social login failed. Ensure OAuth was completed in the browser popup first.',
480 'email' => null,
481 'response' => $response,
482 ];
483 }
484
485 // Response contains user->user_email and token at top level
486 $user_data = $response['user'] ?? [];
487 $user_email = strtolower(sanitize_email((string) ($user_data['user_email'] ?? '')));
488 $token = sanitize_text_field((string) ($response['token'] ?? ''));
489 $user_key = $user_email !== '' ? wdesignkit_cloud_session_key($user_email) : '';
490
491 if ($user_key !== '' && $token !== '') {
492 $cloud_user_id_social = (string) ($user_data['id'] ?? $user_data['user_id'] ?? $response['user_id'] ?? $response['id'] ?? '');
493 set_transient('wdkit_auth_' . $user_key, [
494 'user_email' => $user_email,
495 'token' => $token,
496 'user_id' => $cloud_user_id_social,
497 ], 7776000); // 90 days
498
499 wdesignkit_mcp_remember_session($user_key);
500 }
501
502 return [
503 'success' => true,
504 'message' => $response['message'] ?? 'Logged in via social account successfully.',
505 'email' => $user_email ?: null,
506 'response' => $response,
507 ];
508 }
509
510 function wdesignkit_mcp_signup(array $input): array {
511 if (!defined('WDKIT_SERVER_API_URL')) {
512 return ['success' => false, 'message' => 'WDesignKit plugin is not active.'];
513 }
514
515 $fullname = sanitize_text_field((string) ($input['fullname'] ?? ''));
516 $raw_email = trim((string) ($input['email'] ?? ''));
517 $password = sanitize_text_field((string) ($input['password'] ?? ''));
518
519 if ($fullname === '' || $raw_email === '' || $password === '') {
520 return ['success' => false, 'message' => 'fullname, email, and password are required.', 'email' => null];
521 }
522
523 // Validate email format before sanitizing — sanitize_email() returns '' for
524 // malformed addresses, which would incorrectly trigger the "required" error above.
525 if (!filter_var($raw_email, FILTER_VALIDATE_EMAIL)) {
526 return ['success' => false, 'message' => 'Invalid email address.', 'email' => null];
527 }
528
529 $email = strtolower(sanitize_email($raw_email));
530 $user_key = wdesignkit_cloud_session_key($email);
531
532 // Clear any existing session before signup
533 delete_transient('wdkit_auth_' . $user_key);
534
535 $response = wdesignkit_mcp_template_cloud_call('signup', [
536 'fullname' => $fullname,
537 'password' => $password,
538 'user_email' => $email,
539 ], 'json');
540
541 if (empty($response['success'])) {
542 return [
543 'success' => false,
544 'message' => $response['message'] ?? $response['massage'] ?? 'Sign up failed.',
545 'email' => null,
546 ];
547 }
548
549 $token = sanitize_text_field((string) ($response['token'] ?? ''));
550
551 if ($token !== '') {
552 $signup_user_data = $response['user'] ?? [];
553 $cloud_user_id_sig = (string) ($signup_user_data['id'] ?? $signup_user_data['user_id'] ?? $response['user_id'] ?? $response['id'] ?? '');
554 set_transient('wdkit_auth_' . $user_key, [
555 'user_email' => $email,
556 'token' => $token,
557 'user_id' => $cloud_user_id_sig,
558 ], 86400); // 1-day session after signup
559
560 wdesignkit_mcp_remember_session($user_key);
561 }
562
563 return [
564 'success' => true,
565 'message' => $response['message'] ?? 'Account created and logged in successfully.',
566 'email' => $email,
567 ];
568 }
569
570 function wdesignkit_mcp_forgot_password(array $input): array {
571 if (!defined('WDKIT_SERVER_API_URL')) {
572 return ['success' => false, 'message' => 'WDesignKit plugin is not active.'];
573 }
574
575 $email = strtolower(sanitize_email((string) ($input['email'] ?? '')));
576
577 if ($email === '') {
578 return ['success' => false, 'message' => 'email is required.'];
579 }
580
581 $response = wdesignkit_mcp_template_cloud_call('password/forgot', [
582 'email' => $email,
583 'site_url' => home_url(),
584 ], 'form');
585
586 $success = !empty($response['success']);
587 $message = $response['message'] ?? $response['massage'] ?? ($success ? 'Password reset email sent.' : 'Failed to send reset email.');
588
589 return [
590 'success' => $success,
591 'message' => $message,
592 ];
593 }
594
595 function wdesignkit_mcp_get_social_login_url(array $input): array {
596 if (!defined('WDKIT_SERVER_API_URL')) {
597 return ['success' => false, 'message' => 'WDesignKit plugin is not active.'];
598 }
599
600 $provider = sanitize_text_field((string) ($input['provider'] ?? ''));
601
602 if (!in_array($provider, ['google', 'facebook'], true)) {
603 return ['success' => false, 'message' => 'provider must be "google" or "facebook".'];
604 }
605
606 // Generate a state token matching the JS keyUniqueID() format:
607 // 6 base-36 alphanumeric chars + 2-digit year suffix (e.g. "ab3f2x26").
608 $year = substr(date('Y'), -2);
609 $state = substr(base_convert(bin2hex(random_bytes(5)), 16, 36), 0, 6) . $year;
610
611 $api_base = rtrim(WDKIT_SERVER_API_URL, '/');
612 $expires_in = 600; // OAuth state tokens are valid for ~10 minutes
613
614 if ($provider === 'google') {
615 $auth_url = add_query_arg([
616 'client_id' => '428406150181-7rui8lmg2m9nkqqahreida3j02apfnim.apps.googleusercontent.com',
617 'redirect_uri' => $api_base . '/api/auth/google/callback-plugin',
618 'response_type' => 'code',
619 'scope' => 'email profile',
620 'state' => $state,
621 ], 'https://accounts.google.com/o/oauth2/auth');
622 } else {
623 $auth_url = add_query_arg([
624 'client_id' => '590712039607331',
625 'redirect_uri' => $api_base . '/api/auth/facebook/callback-plugin',
626 'response_type' => 'code',
627 'scope' => 'email',
628 'state' => $state,
629 ], 'https://www.facebook.com/v12.0/dialog/oauth');
630 }
631
632 return [
633 'success' => true,
634 'message' => "Open auth_url in a browser popup for the user to authorise with {$provider}, then pass state to wdesignkit/social-login.",
635 'provider' => $provider,
636 'auth_url' => $auth_url,
637 'state' => $state,
638 'expires_in' => $expires_in,
639 ];
640 }
641
642 function wdesignkit_mcp_logout(array $input): array {
643 if (!defined('WDKIT_SERVER_API_URL')) {
644 return ['success' => false, 'message' => 'WDesignKit plugin is not active.'];
645 }
646
647 $auth = wdesignkit_mcp_template_get_auth();
648
649 if (empty($auth['logged_in'])) {
650 return ['success' => true, 'message' => 'Already logged out — no active session found.'];
651 }
652
653 $token = $auth['token'] ?? '';
654 $email = $auth['email'] ?? '';
655
656 // Delete local session transient
657 if ($email !== '') {
658 $user_key = wdesignkit_cloud_session_key($email);
659 delete_transient('wdkit_auth_' . $user_key);
660 }
661
662 // Drop the active-session pointer so no later call resolves the dead session
663 wdesignkit_mcp_forget_session();
664
665 // Clear cached licence data
666 delete_option('wdkit_licence_data');
667
668 // Notify cloud
669 if ($token !== '') {
670 wdesignkit_mcp_template_cloud_call('logout', ['token' => $token], 'json');
671 }
672
673 return ['success' => true, 'message' => 'Logged out successfully.'];
674 }
675