PluginProbe
Media Cloud Sync / 1.2.12
Media Cloud Sync v1.2.12
1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 All 34 releases
media-cloud-sync / includes / compatbility / compatibility.php

compatibility.php in Media Cloud Sync 1.2.12, at includes/compatbility/compatibility.php

262 lines 8.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Dudlewebs\WPMCS;
3
4 defined('ABSPATH') || exit;
5
6 use WP_CLI;
7
8 class Compatibility {
9 private static $instance = null;
10 private $assets_url;
11 private $version;
12 private $token;
13
14 /**
15 * Compatibility constructor.
16 * @since 1.0.0
17 */
18 private function __construct() {
19 $this->assets_url = WPMCS_ASSETS_URL;
20 $this->version = WPMCS_VERSION;
21 $this->token = WPMCS_TOKEN;
22
23 // Initialize setup
24 $this->init();
25 }
26
27 public function init() {
28 /*
29 * WP_Customize_Control
30 * /wp-includes/class-wp-customize_control.php
31 */
32 add_filter('attachment_url_to_postid', [$this, 'customizer_background_image'], 10, 2);
33
34 /*
35 * Legacy filter
36 * 'wpmcs_get_attached_file_copy_back_to_local'
37 */
38 add_filter('wpmcs_get_attached_file', [$this, 'legacy_copy_back_to_local'], 10, 4);
39
40 /*
41 * Regenerate Thumbnails (before v3)
42 * https://wordpress.org/plugins/regenerate-thumbnails/
43 */
44 add_filter('wpmcs_get_attached_file', [$this, 'regenerate_thumbnails_download_file'], 10, 4);
45
46 /**
47 * Regenerate Thumbnails v3+ and other REST-API using plugins that need a local file.
48 */
49 add_filter('rest_dispatch_request', [$this, 'rest_dispatch_request_copy_back_to_local'], 10, 4);
50
51 /*
52 * WP-CLI Compatibility
53 */
54 if (defined('WP_CLI') && class_exists('WP_CLI')) {
55 WP_CLI::add_hook('before_invoke:media regenerate', [$this, 'enable_copy_back_media']);
56 }
57 }
58
59 /**
60 * Filters the REST dispatch request to determine whether route needs compatibility actions.
61 *
62 * @param bool $dispatch_result Dispatch result, will be used if not empty.
63 * @param WP_REST_Request $request Request used to generate the response.
64 * @param string $route Route matched for the request.
65 * @param array $handler Route handler used for the request.
66 *
67 * @return bool
68 */
69 public function rest_dispatch_request_copy_back_to_local($dispatch_result, $request, $route, $handler) {
70 $routes = [
71 '/regenerate-thumbnails/v\d+/regenerate/',
72 ];
73
74 $routes = apply_filters('wpmcs_rest_api_enable_get_attached_file_copy_back_to_local', $routes);
75 $routes = is_array($routes) ? $routes : (array)$routes;
76
77 if (!empty($routes)) {
78 foreach ($routes as $match_route) {
79 if (preg_match('@' . $match_route . '@i', $route)) {
80 $this->enable_copy_back_media();
81 break;
82 }
83 }
84 }
85
86 return $dispatch_result;
87 }
88
89 /**
90 * Enable copying back attachments from provider
91 * and waiting for their metadata to be regenerated
92 * before re-offloading.
93 *
94 * @handles WP_CLI:before_invoke:media regenerate
95 */
96 public function enable_copy_back_media() {
97 add_filter('wpmcs_get_attached_file_copy_back_to_local', '__return_true');
98 }
99
100 /**
101 * Allow the Regenerate Thumbnails plugin to copy the bucket file back to the local
102 * server when the file is missing on the server via get_attached_file.
103 *
104 * @param string $url
105 * @param string $file
106 * @param int $attachment_id
107 *
108 * @return string
109 */
110 public function regenerate_thumbnails_download_file($url, $file, $attachment_id, $item) {
111 return $this->copy_image_to_server_on_action('regeneratethumbnail', true, $url, $file, $attachment_id);
112 }
113
114 /**
115 * Allow any process to trigger the copy back to local with
116 * the filter 'wpmcs_get_attached_file_copy_back_to_local'
117 *
118 * @param string $url
119 * @param string $file
120 * @param int $attachment_id
121 *
122 * @return string
123 */
124 public function legacy_copy_back_to_local($url, $file, $attachment_id, $wpmcs_item) {
125 $copy_back_to_local = apply_filters('wpmcs_get_attached_file_copy_back_to_local', false, $file, $attachment_id, $wpmcs_item);
126 if (false === $copy_back_to_local) {
127 // Not copying back file
128 return $url;
129 }
130
131 if (($file = $this->copy_provider_file_to_server($attachment_id, $file))) {
132 // Return the file if successfully downloaded from S3
133 return $file;
134 }
135
136 // Return S3 URL as a fallback
137 return $url;
138 }
139
140 /**
141 * Show the correct background image in the customizer
142 *
143 * @param int|null $post_id
144 * @param string $url
145 *
146 * @return int|null
147 */
148 public function customizer_background_image($post_id, $url) {
149 if (!is_null($post_id)) {
150 return $post_id;
151 }
152
153 // There seems to be a bug in the WP Customizer whereby sometimes it puts the attachment ID on the URL.
154 if (is_numeric($url)) {
155 $item = Item::get($url);
156
157 // If we found an offloaded Media Library item for that ID, job's a good'n'.
158 if (!Utils::is_empty($item)) {
159 $post_id = $url;
160 }
161 } else {
162 $path = Utils::get_attachment_source_path($url);
163 if (!Utils::is_empty($path)) {
164 $items = Item::instance()->get_items_by_source_paths([$path]);
165 if (!Utils::is_empty($items)) {
166 // If we found an offloaded Media Library item for that path, job's a good'n'.
167 $post_id = $items[0]['source_id'];
168 }
169 }
170 }
171
172 // Must return null if not found.
173 return empty($post_id) ? null : $post_id;
174 }
175
176 /**
177 * Check the current request is a specific one based on action and
178 * optional context
179 *
180 * @param string $action_key
181 * @param bool $ajax
182 * @param null|string|array $context_key
183 *
184 * @return bool
185 */
186 public function maybe_process_on_action($action_key, $ajax, $context_key = null) {
187 if ($ajax !== Utils::is_ajax()) {
188 return false;
189 }
190
191 $var_type = 'GET';
192
193 if (isset($_GET['action'])) {
194 $action = Utils::filter_input('action');
195 } elseif (isset($_POST['action'])) {
196 $var_type = 'POST';
197 $action = Utils::filter_input('action', INPUT_POST);
198 } else {
199 return false;
200 }
201
202 $context_check = true;
203 if (!is_null($context_key)) {
204 $global = constant('INPUT_' . $var_type);
205 $context = Utils::filter_input('context', $global);
206
207 if (is_array($context_key)) {
208 $context_check = in_array($context, $context_key);
209 } else {
210 $context_check = ($context_key === $context);
211 }
212 }
213
214 return ($action_key === sanitize_key($action) && $context_check);
215 }
216
217 /**
218 * Generic method for copying back an S3 file to the server on a specific AJAX action
219 *
220 * @return string
221 */
222 public function copy_image_to_server_on_action($action_key, $ajax, $url, $file, $attachment_id) {
223 if (false === $this->maybe_process_on_action($action_key, $ajax)) {
224 return $url;
225 }
226
227 if (($file = $this->copy_provider_file_to_server($attachment_id, $file))) {
228 // Return the file if successfully downloaded from S3
229 return $file;
230 }
231
232 return $url;
233 }
234
235 /**
236 * Download a file from bucket if the file does not exist locally and places it where
237 * the attachment's file should be.
238 *
239 * @return string|bool File if downloaded, false on failure
240 */
241 public function copy_provider_file_to_server($attachment_id, $file) {
242 // Download files
243 if (!Item::instance()->moveToServerBySourcePath($attachment_id, $file)) {
244 return false;
245 }
246
247 return $file;
248 }
249
250 /**
251 * Get the singleton instance of the Compatibility class.
252 *
253 * @return Compatibility
254 */
255 public static function instance() {
256 if (self::$instance === null) {
257 self::$instance = new self();
258 }
259 return self::$instance;
260 }
261 }
262