PluginProbe
Media Cloud Sync / trunk
Media Cloud Sync vtrunk
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 / integrations / acf.php

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

275 lines 7.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 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=link', array( $this, 'filter_link_server' ) );
58 add_filter( 'acf/update_value/type=text', array( $this->content_filter, 'filter_post_backward' ) );
59 add_filter( 'acf/update_value/type=textarea', array( $this->content_filter, 'filter_post_backward' ) );
60 add_filter( 'acf/update_value/type=wysiwyg', array( $this->content_filter, 'filter_post_backward' ) );
61 add_filter( 'acf/update_value/type=url', array( $this->content_filter, 'filter_post_backward' ) );
62 add_filter( 'acf/update_value/type=link', array( $this, 'filter_link_provider' ) );
63
64 /*
65 * Image Crop Add-on
66 * https://en-gb.wordpress.org/plugins/acf-image-crop-add-on/
67 */
68 if ( class_exists( 'acf_field_image_crop' ) ) {
69 add_filter( 'wp_get_attachment_metadata', array( $this, 'download_image' ), 10, 2 );
70 add_filter( 'sanitize_file_name', array( $this, 'remove_original_after_download' ) );
71 }
72
73 /*
74 * Rewrite URLs in field and field group config.
75 */
76 add_filter( 'acf/load_fields', array( $this, 'acf_load_config' ) );
77 add_filter( 'acf/load_field_group', array( $this, 'acf_load_config' ) );
78 }
79
80 /**
81 * Rewrites URLs from server to remote inside ACF field and field group config. If the
82 * rewriting process fails, it will return the original config.
83 *
84 * @handles acf/load_fields
85 * @handles acf/load_field_group
86 *
87 * @param array $config
88 *
89 * @return array
90 */
91 public function acf_load_config( array $config ): array {
92 try {
93 $filtered_config = Utils::maybe_unserialize( $this->content_filter->filter_post( Utils::maybe_serialize( $config ) ) );
94 } catch ( Exception $e ) {
95 return $config;
96 }
97
98 return is_array( $filtered_config ) ? $filtered_config : $config;
99 }
100
101 /**
102 * Remove the original image downloaded for the cropping after it has been processed
103 *
104 * @param string $filename
105 *
106 * @return mixed
107 */
108 public function remove_original_after_download( $filename ) {
109 $this->maybe_remove_original_after_download();
110
111 return $filename;
112 }
113
114 /**
115 * Remove the original image from the server
116 *
117 * @return bool|WP_Error
118 */
119 public function maybe_remove_original_after_download() {
120 if ( false === $this->compatibility->maybe_process_on_action( 'acf_image_crop_perform_crop', true ) ) {
121 return false;// Not ACF crop process
122 }
123
124 $original_attachment_id = Utils::filter_input( 'id', INPUT_POST, FILTER_VALIDATE_INT );
125
126 if ( ! isset( $original_attachment_id ) ) {
127 // Can't find the original attachment id
128 return false; // Attachment ID not available
129 }
130
131 $item = Item::instance()->get( $original_attachment_id );
132
133 if ( ! $item ) {
134 return false; //Attachment not offloaded
135 }
136
137 if ( ! Utils::get_meta($original_attachment_id, 'acf_cropped_to_remove', false) ) {
138 // Original attachment should exist serverly, no need to delete
139 return false; //Attachment not to be removed from server
140 }
141
142 // Remove the original file from the server
143 Item::instance()->may_be_delete_server_files_by_id($original_attachment_id, 'media_library', true);
144
145 // Remove marker
146 Utils::delete_meta($original_attachment_id, 'acf_cropped_to_remove');
147
148 return true;
149 }
150
151
152
153 /**
154 * Copy back the S3 image for cropping
155 *
156 * @param array $data
157 * @param int $post_id
158 *
159 * @return array
160 */
161 public function download_image( $data, $post_id ) {
162 $this->maybe_download_image( $post_id );
163
164 return $data;
165 }
166
167
168 /**
169 * Copy back the S3 image
170 *
171 * @param int $post_id
172 *
173 * @return bool|WP_Error
174 */
175 public function maybe_download_image( $post_id ) {
176 if ( false === $this->compatibility->maybe_process_on_action( 'acf_image_crop_perform_crop', true ) ) {
177 return false; // Skip not a proper action
178 }
179
180 $file = get_attached_file( $post_id, true );
181
182 if ( file_exists( $file ) ) {
183 return false; // skip file already exist
184 }
185
186 $item = Item::instance()->get( $post_id );
187
188 if ( ! $item ) {
189 return false; // Failed not offloaded
190 }
191
192 $callers = debug_backtrace(); // phpcs:ignore
193 foreach ( $callers as $caller ) {
194 if ( isset( $caller['function'] ) && 'image_downsize' === $caller['function'] ) {
195 // Don't copy when downsizing the image, which would result in bringing back
196 // the newly cropped image from S3.
197 return false; // 'Skip when Copying back cropped file'
198 }
199 }
200
201 // Copy back the original file for cropping
202 $result = $this->compatibility->copy_provider_file_to_server( $post_id, $file );
203
204 if ( false === $result ) {
205 return false; //Copy back failed
206 }
207
208 // Mark the attachment so we know to remove it later after the crop
209 Utils::update_meta($post_id, 'acf_cropped_to_remove', true);
210
211 return true;
212 }
213
214
215 /**
216 * Filter a link field's URL from server to provider.
217 *
218 * @param array $link
219 *
220 * @return array
221 */
222 public function filter_link_server( $link ) {
223 if ( is_array( $link ) && ! empty( $link['url'] ) ) {
224 $url = $this->content_filter->filter_post( $link['url'] );
225
226 if ( ! empty( $url ) ) {
227 $link['url'] = $url;
228 }
229 }
230
231 return $link;
232 }
233
234
235 /**
236 * Filter a link field's URL from provider to server.
237 *
238 * @param array $link
239 *
240 * @return array
241 */
242 public function filter_link_provider( $link ) {
243 if ( is_array( $link ) && ! empty( $link['url'] ) ) {
244 $url = $this->content_filter->filter_post_backward( $link['url'] );
245
246 if ( ! empty( $url ) ) {
247 $link['url'] = $url;
248 }
249 }
250
251 return $link;
252 }
253
254
255 /**
256 * Is installed?
257 *
258 * @return bool
259 */
260 public static function is_installed(): bool {
261 return class_exists( 'acf', false );
262 }
263
264 /**
265 * Singleton instance
266 */
267 public static function instance() {
268 if (is_null(self::$instance)) {
269 self::$instance = new self();
270 }
271
272 return self::$instance;
273 }
274 }
275