PluginProbe
WindPress – Tailwind CSS integration for WordPress / 3.2.89
WindPress – Tailwind CSS integration for WordPress v3.2.89
3.2.89 3.2.88 3.2.87 3.2.86 3.2.85 3.2.84 3.2.83 3.2.82 3.2.81 trunk 3.0.0 3.0.1 3.0.10 3.0.11 3.0.12 3.0.13 3.0.14 3.0.15 3.0.16 3.0.17 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 All 143 releases
← All changes | src/Api/Admin/Settings/Cache.php +93 -25 3.0.143.2.89 View file →
@@ -14,8 +14,11 @@
14 14 use WIND_PRESS;
15 15 use WindPress\WindPress\Api\AbstractApi;
16 16 use WindPress\WindPress\Api\ApiInterface;
17 17 use WindPress\WindPress\Core\Cache as CoreCache;
18 +use WindPress\WindPress\Core\Scanner\BuildState;
19 +use WindPress\WindPress\Core\Scanner\SourceIndex;
20 +use WindPress\WindPress\Core\Scanner\SourceRevision;
18 21 use WindPress\WindPress\Utils\Common;
19 22 use WindPress\WindPress\Utils\Debug;
20 23 use WP_REST_Request;
21 24 use WP_REST_Response;
@@ -24,61 +27,126 @@
24 27 {
25 28 public function __construct()
26 29 {
27 30 }
28 - public function get_prefix() : string
31 + public function get_prefix(): string
29 32 {
30 33 return 'admin/settings/cache';
31 34 }
32 - public function register_custom_endpoints() : void
35 + public function register_custom_endpoints(): void
33 36 {
34 - \register_rest_route(self::API_NAMESPACE, $this->get_prefix() . '/index', ['methods' => WP_REST_Server::READABLE, 'callback' => fn(\WP_REST_Request $wprestRequest): \WP_REST_Response => $this->index($wprestRequest), 'permission_callback' => fn(\WP_REST_Request $wprestRequest): bool => $this->permission_callback($wprestRequest)]);
35 - \register_rest_route(self::API_NAMESPACE, $this->get_prefix() . '/store', ['methods' => WP_REST_Server::CREATABLE, 'callback' => fn(\WP_REST_Request $wprestRequest): \WP_REST_Response => $this->store($wprestRequest), 'permission_callback' => fn(\WP_REST_Request $wprestRequest): bool => $this->permission_callback($wprestRequest)]);
36 - \register_rest_route(self::API_NAMESPACE, $this->get_prefix() . '/providers', ['methods' => WP_REST_Server::READABLE, 'callback' => fn(\WP_REST_Request $wprestRequest): \WP_REST_Response => $this->providers($wprestRequest), 'permission_callback' => fn(\WP_REST_Request $wprestRequest): bool => $this->permission_callback($wprestRequest)]);
37 - \register_rest_route(self::API_NAMESPACE, $this->get_prefix() . '/providers/scan', ['methods' => WP_REST_Server::CREATABLE, 'callback' => fn(\WP_REST_Request $wprestRequest): \WP_REST_Response => $this->providers_scan($wprestRequest), 'permission_callback' => fn(\WP_REST_Request $wprestRequest): bool => $this->permission_callback($wprestRequest)]);
37 + register_rest_route(self::API_NAMESPACE, $this->get_prefix() . '/index', ['methods' => WP_REST_Server::READABLE, 'callback' => fn(\WP_REST_Request $wprestRequest): \WP_REST_Response => $this->index($wprestRequest), 'permission_callback' => fn(\WP_REST_Request $wprestRequest): bool => $this->permission_callback($wprestRequest)]);
38 + register_rest_route(self::API_NAMESPACE, $this->get_prefix() . '/store', ['methods' => WP_REST_Server::CREATABLE, 'callback' => fn(\WP_REST_Request $wprestRequest): \WP_REST_Response => $this->store($wprestRequest), 'permission_callback' => fn(\WP_REST_Request $wprestRequest): bool => $this->permission_callback($wprestRequest)]);
39 + register_rest_route(self::API_NAMESPACE, $this->get_prefix() . '/providers', ['methods' => WP_REST_Server::READABLE, 'callback' => fn(\WP_REST_Request $wprestRequest): \WP_REST_Response => $this->providers($wprestRequest), 'permission_callback' => fn(\WP_REST_Request $wprestRequest): bool => $this->permission_callback($wprestRequest)]);
40 + register_rest_route(self::API_NAMESPACE, $this->get_prefix() . '/providers/scan', ['methods' => WP_REST_Server::CREATABLE, 'callback' => fn(\WP_REST_Request $wprestRequest): \WP_REST_Response => $this->providers_scan($wprestRequest), 'permission_callback' => fn(\WP_REST_Request $wprestRequest): bool => $this->permission_callback($wprestRequest)]);
38 41 }
39 - public function index(WP_REST_Request $wprestRequest) : WP_REST_Response
42 + public function index(WP_REST_Request $wprestRequest): WP_REST_Response
40 43 {
41 44 $cache_path = CoreCache::get_cache_path(CoreCache::CSS_CACHE_FILE);
42 - $cache = ['last_generated' => null, 'file_url' => null, 'file_size' => \false];
43 - if (\file_exists($cache_path) && \is_readable($cache_path)) {
45 + clearstatcache(\true, $cache_path);
46 + $build_state = BuildState::get();
47 + $cache = ['last_generated' => null, 'last_full_build' => null, 'file_url' => null, 'file_size' => \false, 'generation' => $build_state['generation'], 'source_revision' => SourceRevision::get()];
48 + if (file_exists($cache_path) && is_readable($cache_path)) {
44 49 $cache['file_url'] = CoreCache::get_cache_url(CoreCache::CSS_CACHE_FILE);
45 - $cache['last_generated'] = \filemtime($cache_path);
46 - $cache['file_size'] = \filesize($cache_path);
50 + $cache['last_generated'] = filemtime($cache_path);
51 + $cache['file_size'] = filesize($cache_path);
52 + $cache['last_full_build'] = $build_state['last_full_build'] ?? null;
47 53 }
48 54 return new WP_REST_Response(['cache' => $cache]);
49 55 }
50 - public function store(WP_REST_Request $wprestRequest) : WP_REST_Response
56 + public function store(WP_REST_Request $wprestRequest): WP_REST_Response
51 57 {
52 58 $payload = $wprestRequest->get_json_params();
59 + if (!is_array($payload) || !isset($payload['content']) || !is_string($payload['content']) || isset($payload['expected_generation']) && !is_string($payload['expected_generation']) || isset($payload['expected_source_revision']) && !is_string($payload['expected_source_revision']) || isset($payload['sourcemap']) && !is_string($payload['sourcemap']) || isset($payload['full_build']) && !is_bool($payload['full_build']) && !is_int($payload['full_build'])) {
60 + return new WP_REST_Response(['status' => 'KO', 'message' => __('The cache payload is invalid.', 'windpress')], 400);
61 + }
62 + $content = base64_decode($payload['content'], \true);
63 + $sourcemapContent = !empty($payload['sourcemap']) ? base64_decode($payload['sourcemap'], \true) : null;
64 + if ($content === \false || $sourcemapContent === \false) {
65 + return new WP_REST_Response(['status' => 'KO', 'message' => __('The cache content is not valid base64.', 'windpress')], 400);
66 + }
67 + $lease = BuildState::acquire();
68 + if ($lease === null) {
69 + return new WP_REST_Response(['status' => 'KO', 'message' => __('Another cache build is being saved. Retry the build.', 'windpress')], 409);
70 + }
53 71 try {
54 - $content = \sprintf("/*! %s v%s | %s | %s */\n%s", \strtolower(Common::plugin_data('Name')), WIND_PRESS::VERSION, \gmdate('Y-m-d H:i:s', \time()), \strtolower(Common::plugin_data('PluginURI')), \base64_decode($payload['content']));
72 + if (isset($payload['expected_generation']) && !BuildState::matches($payload['expected_generation'])) {
73 + return new WP_REST_Response(['status' => 'KO', 'message' => __('The scan generation has changed. Restart the build.', 'windpress')], 409);
74 + }
75 + if (isset($payload['expected_source_revision']) && !SourceRevision::matches($payload['expected_source_revision'])) {
76 + return new WP_REST_Response(['status' => 'KO', 'message' => __('Source content changed during the scan. Restart the build.', 'windpress')], 409);
77 + }
78 + if ($sourcemapContent !== null) {
79 + CoreCache::save_sourcemap($sourcemapContent);
80 + $content .= "\n/*# sourceMappingURL=" . CoreCache::CSS_SOURCEMAP_FILE . ' */';
81 + } else {
82 + // add a comment at the top of the file
83 + $comment = sprintf("/*! %s v%s | %s | %s */\n", strtolower(Common::plugin_data('Name')), WIND_PRESS::VERSION, gmdate('Y-m-d H:i:s', time()), strtolower(Common::plugin_data('PluginURI')));
84 + $content = $comment . $content;
85 + }
55 86 CoreCache::save_cache($content);
87 + if (!empty($payload['full_build'])) {
88 + BuildState::complete_full_build();
89 + }
90 + return $this->index($wprestRequest);
56 91 } catch (\Throwable $throwable) {
57 - return new WP_REST_Response(['status' => 'KO', 'message' => 'Save cache error: ' . $throwable->getMessage()], 500);
92 + return new WP_REST_Response(['status' => 'KO', 'message' => __('Save cache error: ', 'windpress') . $throwable->getMessage()], 500);
93 + } finally {
94 + BuildState::release($lease);
58 95 }
59 - return $this->index($wprestRequest);
60 96 }
61 - public function providers(WP_REST_Request $wprestRequest) : WP_REST_Response
97 + public function providers(WP_REST_Request $wprestRequest): WP_REST_Response
62 98 {
63 - return new WP_REST_Response(['providers' => CoreCache::get_providers()]);
99 + $providers = CoreCache::get_providers();
100 + // Add installation status to each provider
101 + foreach ($providers as &$provider) {
102 + if (isset($provider['is_installed_active']) && is_callable($provider['is_installed_active'])) {
103 + $provider['is_installed_active'] = $provider['is_installed_active']();
104 + }
105 + }
106 + return new WP_REST_Response(['providers' => $providers]);
64 107 }
65 - public function providers_scan(WP_REST_Request $wprestRequest) : WP_REST_Response
108 + public function providers_scan(WP_REST_Request $wprestRequest): WP_REST_Response
66 109 {
67 110 $stopwatch = Debug::stopwatch();
68 111 $provider_id = $wprestRequest->get_param('provider_id');
69 112 $metadata = $wprestRequest->get_param('metadata') ?? [];
70 - $provider = \array_filter(CoreCache::get_providers(), static fn($provider) => $provider['id'] === $provider_id);
113 + if (!is_string($provider_id) || !is_array($metadata) || isset($metadata['generation']) && !is_string($metadata['generation']) || isset($metadata['source_revision']) && !is_string($metadata['source_revision'])) {
114 + return new WP_REST_Response(['status' => 'KO', 'message' => __('The scan request is invalid.', 'windpress')], 400);
115 + }
116 + $generation = BuildState::get()['generation'];
117 + $source_revision = SourceRevision::get();
118 + if (isset($metadata['generation']) && !hash_equals($generation, $metadata['generation'])) {
119 + return new WP_REST_Response(['status' => 'KO', 'message' => __('The scan generation has changed. Restart the build.', 'windpress')], 409);
120 + }
121 + if (isset($metadata['source_revision']) && !hash_equals($source_revision, $metadata['source_revision'])) {
122 + return new WP_REST_Response(['status' => 'KO', 'message' => __('Source content changed during the scan. Restart the build.', 'windpress')], 409);
123 + }
124 + $metadata += ['next_batch' => \false];
125 + $provider = array_filter(CoreCache::get_providers(), static fn($provider) => $provider['id'] === $provider_id);
71 126 if ($provider === []) {
72 - return new WP_REST_Response(['status' => 'KO', 'message' => 'The provider not found'], 404);
127 + return new WP_REST_Response(['status' => 'KO', 'message' => __('The provider not found', 'windpress')], 404);
73 128 }
74 - $provider = \array_shift($provider);
129 + $provider = array_shift($provider);
75 130 $stopwatch->start('cache-provider:' . $provider['id'], 'cache-provider-scan');
76 131 try {
77 - $result = CoreCache::fetch_contents($provider['callback'], $metadata);
132 + if (array_key_exists('source_index', $metadata)) {
133 + if (($provider['source_index'] ?? 0) !== 1) {
134 + throw new \InvalidArgumentException(__('This provider does not support source indexing.', 'windpress'));
135 + }
136 + $result = SourceIndex::scan('provider:' . $provider_id, $metadata, static function (array $page_metadata) use ($provider): array {
137 + return CoreCache::fetch_contents($provider['callback'], $page_metadata);
138 + });
139 + } else {
140 + $result = CoreCache::fetch_contents($provider['callback'], $metadata);
141 + }
142 + if (isset($metadata['source_revision']) && !SourceRevision::matches($source_revision)) {
143 + throw new \RuntimeException(__('Source content changed during the scan. Restart the build.', 'windpress'), 409);
144 + }
78 145 } catch (\Throwable $throwable) {
79 - return new WP_REST_Response(['status' => 'KO', 'message' => 'Provider error: ' . $throwable->getMessage()], 500);
146 + return new WP_REST_Response(['status' => 'KO', 'message' => __('Provider error: ', 'windpress') . $throwable->getMessage()], $throwable instanceof \InvalidArgumentException ? 400 : ($throwable->getCode() === 409 ? 409 : 500));
147 + } finally {
148 + $stopwatchEvent = $stopwatch->stop('cache-provider:' . $provider['id']);
80 149 }
81 - $stopwatchEvent = $stopwatch->stop('cache-provider:' . $provider['id']);
82 - return new WP_REST_Response(['metadata' => ['provider_id' => $provider['id'], 'provider_name' => $provider['name'], 'profiling' => ['unix_timestamp' => \time(), 'duration' => $stopwatchEvent->getDuration() . ' ms', 'memory' => \sprintf('%.2F MiB', $stopwatchEvent->getMemory() / 1024 / 1024)], 'next_batch' => $result['metadata']['next_batch'] ?? \false], 'contents' => $result['contents'], 'status' => 'OK']);
150 + return new WP_REST_Response(['metadata' => array_merge($result['metadata'], ['provider_id' => $provider['id'], 'provider_name' => $provider['name'], 'generation' => $generation, 'source_revision' => $source_revision, 'profiling' => ['unix_timestamp' => time(), 'duration' => $stopwatchEvent->getDuration() . ' ms', 'memory' => sprintf('%.2F MiB', $stopwatchEvent->getMemory() / 1024 / 1024)], 'next_batch' => $result['metadata']['next_batch'] ?? \false, 'total_batches' => $result['metadata']['total_batches'] ?? \false]), 'contents' => $result['contents'], 'status' => 'OK']);
83 151 }
84 152 }