PluginProbe
Media Cloud Sync / 1.4.2
Media Cloud Sync v1.4.2
1.4.2 1.4.1 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 All 36 releases
media-cloud-sync / includes / integrations / acf.php

acf.php in Media Cloud Sync 1.4.2, at includes/integrations/acf.php

291 lines 7.9 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 DirectoryIterator;
7 use Exception;
8
9 /**
10 * ACF Compatibility.
11 *
12 * Loaded by the autoloader; activation is gated via `is_installed()` in Integration::init().
13 *
14 * @since 1.0.0
15 */
16 class Acf {
17 private static $instance = null;
18 private $assets_url;
19 private $version;
20 private $token;
21
22 protected $settings;
23 protected $content_filter;
24 protected $compatibility;
25
26 /**
27 * Admin constructor.
28 * @since 1.0.0
29 */
30 private function __construct() {
31 $this->assets_url = WPMCS_ASSETS_URL;
32 $this->version = WPMCS_VERSION;
33 $this->token = WPMCS_TOKEN;
34 $this->settings = Utils::get_settings();
35 $this->content_filter = FilterContent::instance();
36 $this->compatibility = Compatibility::instance();
37
38 $this->registerActions();
39 }
40
41 /**
42 * Register integration access
43 * @since 1.0.0
44 * @access public
45 *
46 * @return void
47 */
48 public function registerActions() {
49 /*
50 * Content Filtering
51 */
52
53 add_filter( 'acf/load_value/type=text', array( $this->content_filter, 'filter_post' ) );
54 add_filter( 'acf/load_value/type=textarea', array( $this->content_filter, 'filter_post' ) );
55 add_filter( 'acf/load_value/type=wysiwyg', array( $this->content_filter, 'filter_post' ) );
56 add_filter( 'acf/load_value/type=url', array( $this->content_filter, 'filter_post' ) );
57 add_filter( 'acf/load_value/type=oembed', array( $this->content_filter, 'filter_post' ) );
58 add_filter( 'acf/load_value/type=link', array( $this, 'filter_link_server' ) );
59 add_filter( 'acf/update_value/type=text', array( $this->content_filter, 'filter_post_backward' ) );
60 add_filter( 'acf/update_value/type=textarea', array( $this->content_filter, 'filter_post_backward' ) );
61 add_filter( 'acf/update_value/type=wysiwyg', array( $this->content_filter, 'filter_post_backward' ) );
62 add_filter( 'acf/update_value/type=url', array( $this->content_filter, 'filter_post_backward' ) );
63 add_filter( 'acf/update_value/type=oembed', array( $this->content_filter, 'filter_post_backward' ) );
64 add_filter( 'acf/update_value/type=link', array( $this, 'filter_link_provider' ) );
65
66 /*
67 * Image Crop Add-on
68 * https://en-gb.wordpress.org/plugins/acf-image-crop-add-on/
69 */
70 if ( class_exists( 'acf_field_image_crop' ) ) {
71 add_filter( 'wp_get_attachment_metadata', array( $this, 'download_image' ), 10, 2 );
72 add_filter( 'sanitize_file_name', array( $this, 'remove_original_after_download' ) );
73 add_filter( 'wpmcs_do_reupload_media', array( $this, 'force_reupload_during_crop' ), 10, 3 );
74 }
75
76 /*
77 * Rewrite URLs in field and field group config.
78 */
79 add_filter( 'acf/load_fields', array( $this, 'acf_load_config' ) );
80 add_filter( 'acf/load_field_group', array( $this, 'acf_load_config' ) );
81 }
82
83 /**
84 * Rewrites URLs from server to remote inside ACF field and field group config. If the
85 * rewriting process fails, it will return the original config.
86 *
87 * @handles acf/load_fields
88 * @handles acf/load_field_group
89 *
90 * @param array $config
91 *
92 * @return array
93 */
94 public function acf_load_config( array $config ): array {
95 try {
96 $filtered_config = Utils::maybe_unserialize( $this->content_filter->filter_post( Utils::maybe_serialize( $config ) ) );
97 } catch ( Exception $e ) {
98 return $config;
99 }
100
101 return is_array( $filtered_config ) ? $filtered_config : $config;
102 }
103
104 /**
105 * Remove the original image downloaded for the cropping after it has been processed
106 *
107 * @param string $filename
108 *
109 * @return mixed
110 */
111 public function remove_original_after_download( $filename ) {
112 $this->maybe_remove_original_after_download();
113
114 return $filename;
115 }
116
117 /**
118 * Remove the original image from the server
119 *
120 * @return bool|WP_Error
121 */
122 public function maybe_remove_original_after_download() {
123 if ( false === $this->compatibility->maybe_process_on_action( 'acf_image_crop_perform_crop', true ) ) {
124 return false;// Not ACF crop process
125 }
126
127 $original_attachment_id = Utils::filter_input( 'id', INPUT_POST, FILTER_VALIDATE_INT );
128
129 if ( ! isset( $original_attachment_id ) ) {
130 // Can't find the original attachment id
131 return false; // Attachment ID not available
132 }
133
134 $item = Item::instance()->get( $original_attachment_id );
135
136 if ( ! $item ) {
137 return false; //Attachment not offloaded
138 }
139
140 if ( ! Utils::get_meta($original_attachment_id, 'acf_cropped_to_remove', false) ) {
141 // Original attachment should exist serverly, no need to delete
142 return false; //Attachment not to be removed from server
143 }
144
145 // Remove the original file from the server
146 Item::instance()->may_be_delete_server_files_by_id($original_attachment_id, 'media_library', true);
147
148 // Remove marker
149 Utils::delete_meta($original_attachment_id, 'acf_cropped_to_remove');
150
151 return true;
152 }
153
154 /**
155 * ACF Image Crop Add-on always crops to the field's one fixed configured
156 * size, so declared dimensions never change between crops — the same blind
157 * spot shouldForceReupload() has for a flip/180° rotate. Force it explicitly.
158 * @since 1.4.3
159 */
160 public function force_reupload_during_crop( $do_reupload, $attachment_id, $source_type ) {
161 if ( $do_reupload ) {
162 return $do_reupload;
163 }
164 return $this->compatibility->maybe_process_on_action( 'acf_image_crop_perform_crop', true ) ? true : $do_reupload;
165 }
166
167
168
169 /**
170 * Copy back the S3 image for cropping
171 *
172 * @param array $data
173 * @param int $post_id
174 *
175 * @return array
176 */
177 public function download_image( $data, $post_id ) {
178 $this->maybe_download_image( $post_id );
179
180 return $data;
181 }
182
183
184 /**
185 * Copy back the S3 image
186 *
187 * @param int $post_id
188 *
189 * @return bool|WP_Error
190 */
191 public function maybe_download_image( $post_id ) {
192 if ( false === $this->compatibility->maybe_process_on_action( 'acf_image_crop_perform_crop', true ) ) {
193 return false; // Skip not a proper action
194 }
195
196 $file = get_attached_file( $post_id, true );
197
198 if ( file_exists( $file ) ) {
199 return false; // skip file already exist
200 }
201
202 $item = Item::instance()->get( $post_id );
203
204 if ( ! $item ) {
205 return false; // Failed not offloaded
206 }
207
208 $callers = debug_backtrace(); // phpcs:ignore
209 foreach ( $callers as $caller ) {
210 if ( isset( $caller['function'] ) && 'image_downsize' === $caller['function'] ) {
211 // Don't copy when downsizing the image, which would result in bringing back
212 // the newly cropped image from S3.
213 return false; // 'Skip when Copying back cropped file'
214 }
215 }
216
217 // Copy back the original file for cropping
218 $result = $this->compatibility->copy_provider_file_to_server( $post_id, $file );
219
220 if ( false === $result ) {
221 return false; //Copy back failed
222 }
223
224 // Mark the attachment so we know to remove it later after the crop
225 Utils::update_meta($post_id, 'acf_cropped_to_remove', true);
226
227 return true;
228 }
229
230
231 /**
232 * Filter a link field's URL from server to provider.
233 *
234 * @param array $link
235 *
236 * @return array
237 */
238 public function filter_link_server( $link ) {
239 if ( is_array( $link ) && ! empty( $link['url'] ) ) {
240 $url = $this->content_filter->filter_post( $link['url'] );
241
242 if ( ! empty( $url ) ) {
243 $link['url'] = $url;
244 }
245 }
246
247 return $link;
248 }
249
250
251 /**
252 * Filter a link field's URL from provider to server.
253 *
254 * @param array $link
255 *
256 * @return array
257 */
258 public function filter_link_provider( $link ) {
259 if ( is_array( $link ) && ! empty( $link['url'] ) ) {
260 $url = $this->content_filter->filter_post_backward( $link['url'] );
261
262 if ( ! empty( $url ) ) {
263 $link['url'] = $url;
264 }
265 }
266
267 return $link;
268 }
269
270
271 /**
272 * Is installed?
273 *
274 * @return bool
275 */
276 public static function is_installed(): bool {
277 return class_exists( 'acf', false );
278 }
279
280 /**
281 * Singleton instance
282 */
283 public static function instance() {
284 if (is_null(self::$instance)) {
285 self::$instance = new self();
286 }
287
288 return self::$instance;
289 }
290 }
291