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
windpress / src / Api / Admin / Settings / Cache.php

Cache.php in WindPress – Tailwind CSS integration for WordPress 3.2.89, at src/Api/Admin/Settings/Cache.php

153 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * This file is part of the WindPress package.
5 *
6 * (c) Joshua Gugun Siagian <suabahasa@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11 declare (strict_types=1);
12 namespace WindPress\WindPress\Api\Admin\Settings;
13
14 use WIND_PRESS;
15 use WindPress\WindPress\Api\AbstractApi;
16 use WindPress\WindPress\Api\ApiInterface;
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;
21 use WindPress\WindPress\Utils\Common;
22 use WindPress\WindPress\Utils\Debug;
23 use WP_REST_Request;
24 use WP_REST_Response;
25 use WP_REST_Server;
26 class Cache extends AbstractApi implements ApiInterface
27 {
28 public function __construct()
29 {
30 }
31 public function get_prefix(): string
32 {
33 return 'admin/settings/cache';
34 }
35 public function register_custom_endpoints(): void
36 {
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)]);
41 }
42 public function index(WP_REST_Request $wprestRequest): WP_REST_Response
43 {
44 $cache_path = CoreCache::get_cache_path(CoreCache::CSS_CACHE_FILE);
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)) {
49 $cache['file_url'] = CoreCache::get_cache_url(CoreCache::CSS_CACHE_FILE);
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;
53 }
54 return new WP_REST_Response(['cache' => $cache]);
55 }
56 public function store(WP_REST_Request $wprestRequest): WP_REST_Response
57 {
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 }
71 try {
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 }
86 CoreCache::save_cache($content);
87 if (!empty($payload['full_build'])) {
88 BuildState::complete_full_build();
89 }
90 return $this->index($wprestRequest);
91 } catch (\Throwable $throwable) {
92 return new WP_REST_Response(['status' => 'KO', 'message' => __('Save cache error: ', 'windpress') . $throwable->getMessage()], 500);
93 } finally {
94 BuildState::release($lease);
95 }
96 }
97 public function providers(WP_REST_Request $wprestRequest): WP_REST_Response
98 {
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]);
107 }
108 public function providers_scan(WP_REST_Request $wprestRequest): WP_REST_Response
109 {
110 $stopwatch = Debug::stopwatch();
111 $provider_id = $wprestRequest->get_param('provider_id');
112 $metadata = $wprestRequest->get_param('metadata') ?? [];
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);
126 if ($provider === []) {
127 return new WP_REST_Response(['status' => 'KO', 'message' => __('The provider not found', 'windpress')], 404);
128 }
129 $provider = array_shift($provider);
130 $stopwatch->start('cache-provider:' . $provider['id'], 'cache-provider-scan');
131 try {
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 }
145 } catch (\Throwable $throwable) {
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']);
149 }
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']);
151 }
152 }
153