| Code Coverage
| Lines | Functions and Methods | Classes and Traits
Total | 95.24% covered (success) | 95.24% | 20 / 21 | 75.00% covered (warning) | 75.00% | 3 / 4 | CRAP | 0.00% covered (danger) | 0.00% | 0 / 1
IndexationPage | 95.24% covered (success) | 95.24% | 20 / 21 | 75.00% covered (warning) | 75.00% | 3 / 4 | 9 | 0.00% covered (danger) | 0.00% | 0 / 1
get | 100.00% covered (success) | 100.00% | 1 / 1 | 100.00% covered (success) | 100.00% | 1 / 1 | 1 |
save | 100.00% covered (success) | 100.00% | 12 / 12 | 100.00% covered (success) | 100.00% | 1 / 1 | 3 |
clear | 100.00% covered (success) | 100.00% | 1 / 1 | 100.00% covered (success) | 100.00% | 1 / 1 | 1 |
isValid | 85.71% covered (warning) | 85.71% | 6 / 7 | 0.00% covered (danger) | 0.00% | 0 / 1 | 4.05 |

1 | <?php
2 | /**
3 | * IndexationPage Manager (MVP-001, 2026-08-01).
4 | *
5 | * Client-side storage + retrieval for the operator's indexation page URL.
6 | * The URL is stored in WP options and submitted to the server via
7 | * POST /v1/indexation-page/register (HMAC-signed).
8 | *
9 | * Storage: WP option 'swapads_client_indexation_page' (string URL or '').
10 | *
11 | * @package SwapAds\Client\Indexation
12 | *
13 | * @since 1.5.7
14 | */
15 |
16 | declare(strict_types=1);
17 |
18 | namespace SwapAds\Client\Indexation;
19 |
20 | /**
21 | * Class IndexationPage.
22 | *
23 | * @since 1.5.7
24 | */
25 | final class IndexationPage
26 | {
27 | public const OPTION_KEY = 'swapads_client_indexation_page';
28 |
29 | public const MAX_LENGTH = 512;
30 |
31 | /**
32 | * Get the stored indexation page URL, or empty string if not set.
33 | *
34 | * @return string URL or ''.
35 | *
36 | * @since 1.5.7
37 | */
38 | public static function get(): string
39 | {
40 | return (string) get_option(self::OPTION_KEY, '');
41 | }
42 |
43 | /**
44 | * Validate + store the indexation page URL locally.
45 | *
46 | * @param string $url URL to store.
47 | *
48 | * @return array<string, mixed> Result {success: bool, error?: string, url: string}.
49 | *
50 | * @since 1.5.7
51 | */
52 | public static function save(string $url): array
53 | {
54 | $url = trim($url);
55 | if ($url === '') {
56 | // Allow clearing the value.
57 | update_option(self::OPTION_KEY, '');
58 | return ['success' => true, 'url' => ''];
59 | }
60 |
61 | if (!self::isValid($url)) {
62 | return [
63 | 'success' => false,
64 | 'error' => 'Indexation page URL must be a valid http(s) URL.',
65 | 'url' => $url,
66 | ];
67 | }
68 |
69 | update_option(self::OPTION_KEY, $url);
70 | return ['success' => true, 'url' => $url];
71 | }
72 |
73 | /**
74 | * Delete the stored URL (empty string).
75 | *
76 | * @return bool True if option was deleted/updated.
77 | *
78 | * @since 1.5.7
79 | */
80 | public static function clear(): bool
81 | {
82 | return (bool) update_option(self::OPTION_KEY, '');
83 | }
84 |
85 | /**
86 | * Validate that the URL is well-formed.
87 | *
88 | * @param string $url URL.
89 | *
90 | * @return bool True if valid.
91 | *
92 | * @since 1.5.7
93 | */
94 | public static function isValid(string $url): bool
95 | {
96 | if (strlen($url) > self::MAX_LENGTH) {
97 | return false;
98 | }
99 | if (!preg_match('#^https?://#i', $url)) {
100 | return false;
101 | }
102 | if (!filter_var($url, FILTER_VALIDATE_URL)) {
103 | return false;
104 | }
105 | return true;
106 | }
107 | }