Skip to content

Commit 4eec5ce

Browse files
author
David Cramer
authored
Merge pull request #54 from cloudinary/fix/dual-sync
Fix/dual-sync (CLOUD-375)
2 parents d165786 + ee06184 commit 4eec5ce

File tree

10 files changed

+155
-56
lines changed

10 files changed

+155
-56
lines changed

cloudinary-image-management-and-manipulation-in-the-cloud-cdn/cloudinary.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Plugin Name: Cloudinary
44
* Plugin URI: https://cloudinary.com/documentation/wordpress_integration
55
* Description: With the Cloudinary plugin, you can upload and manage your media assets in the cloud, then deliver them to your users through a fast content delivery network, improving your website’s loading speed and overall user experience. Apply multiple transformations and take advantage of a full digital asset management solution without leaving WordPress.
6-
* Version: 2.0.2
6+
* Version: 2.0.3
77
* Author: Cloudinary Ltd., XWP
88
* Author URI: https://cloudinary.com/
99
* License: GPLv2+

cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/class-media.php

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,6 @@ public function apply_default_transformations( array $transformations, $type = '
497497
$global = $this->global_transformations->globals[ $type ];
498498
$default = array();
499499
if ( 'video' === $type ) {
500-
$default['quality'] = 'auto';
501500
if ( isset( $global['video_limit_bitrate'] ) && 'on' === $global['video_limit_bitrate'] ) {
502501
$default['bit_rate'] = $global['video_bitrate'] . 'k';
503502
}
@@ -1243,7 +1242,9 @@ public function get_post_meta( $post_id, $key, $single = false ) {
12431242
*/
12441243
public function build_cached_meta( $post_id, $key, $single ) {
12451244
$data = get_post_meta( $post_id, $key, $single );
1246-
$this->update_post_meta( $post_id, $key, $data );
1245+
if ( '' !== $data ) {
1246+
$this->update_post_meta( $post_id, $key, $data );
1247+
}
12471248

12481249
return $data;
12491250
}
@@ -1266,6 +1267,23 @@ public function update_post_meta( $post_id, $key, $data ) {
12661267
update_post_meta( $post_id, $key, $data );
12671268
}
12681269

1270+
/**
1271+
* Delete cloudinary metadata.
1272+
*
1273+
* @param int $post_id The attachment ID.
1274+
* @param string $key The meta key to get.
1275+
*/
1276+
public function delete_post_meta( $post_id, $key ) {
1277+
$meta_data = wp_get_attachment_metadata( $post_id, true );
1278+
if ( is_array( $meta_data ) && isset( $meta_data[ Sync::META_KEYS['cloudinary'] ] ) && is_array( $meta_data[ Sync::META_KEYS['cloudinary'] ] ) ) {
1279+
// Only do this side if has been set before.
1280+
unset( $meta_data[ Sync::META_KEYS['cloudinary'] ][ $key ] );
1281+
wp_update_attachment_metadata( $post_id, $meta_data );
1282+
}
1283+
// Delete meta data.
1284+
delete_post_meta( $post_id, $key );
1285+
}
1286+
12691287
/**
12701288
* Setup the hooks and base_url if configured.
12711289
*/

cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/class-rest-api.php

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,20 @@ public function background_request( $endpoint, $params, $method = 'POST' ) {
6363
// Setup a call for a background sync.
6464
$params['nonce'] = wp_create_nonce( 'wp_rest' );
6565
$args = array(
66-
'timeout' => 1,
67-
'blocking' => false,
68-
'method' => $method,
69-
'headers' => array(),
70-
'body' => $params,
66+
'timeout' => 1,
67+
'blocking' => false,
68+
'sslverify' => false,
69+
'method' => $method,
70+
'headers' => array(),
71+
'body' => $params,
7172
);
7273
if ( is_user_logged_in() ) {
7374
// Setup cookie.
7475
$logged_cookie = wp_parse_auth_cookie( '', 'logged_in' );
7576
array_pop( $logged_cookie ); // remove the scheme.
7677

7778
// Add logged in cookie to request.
78-
$args['cookies'] = array(
79+
$args['cookies'] = array(
7980
new \WP_Http_Cookie(
8081
array(
8182
'name' => LOGGED_IN_COOKIE,
@@ -85,8 +86,9 @@ public function background_request( $endpoint, $params, $method = 'POST' ) {
8586
$url
8687
),
8788
);
88-
$args['headers']['X-WP-Nonce'] = $params['nonce'];
89+
8990
}
91+
$args['headers']['X-WP-Nonce'] = $params['nonce'];
9092

9193
// Send request.
9294
wp_safe_remote_request( $url, $args );

cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/media/class-upgrade.php

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ public function check_cloudinary_version( $cloudinary_id, $attachment_id ) {
5555
*/
5656
if ( ! empty( $meta['cloudinary'] ) && empty( $public_id ) ) {
5757
$cloudinary_id = $this->convert_cloudinary_version( $attachment_id );
58+
} elseif ( ! empty( $public_id ) ) {
59+
// Has public ID, but not fully down synced.
60+
$cloudinary_id = $public_id;
5861
}
5962
}
6063

@@ -103,29 +106,19 @@ function ( $val ) use ( $media ) {
103106
// Remove extension.
104107
$path = pathinfo( $public_id );
105108
$public_id = strstr( $public_id, '.' . $path['extension'], true );
106-
// Save public ID.
107109
$this->media->update_post_meta( $attachment_id, Sync::META_KEYS['public_id'], $public_id );
108110

109-
// Setup a call for a background sync.
110-
$params = array(
111-
'attachment_id' => $attachment_id,
112-
'src' => $file,
113-
'transformations' => $media->get_transformations_from_string( $file ),
114-
'filename' => basename( $file ),
115-
);
116-
$media->plugin->components['api']->background_request( 'asset', $params );
117-
118111
return $public_id;
119112
}
120113

121114
/**
122115
* Setup hooks for the filters.
123116
*/
124117
public function setup_hooks() {
125-
add_filter( 'cloudinary_id', array( $this, 'check_cloudinary_version' ), 9, 2 ); // Priority 9, to take preference over prep_on_demand_upload.
118+
add_filter( 'cloudinary_id', array( $this, 'check_cloudinary_version' ), 10, 2 ); // Priority 10, to allow prep_on_demand_upload.
126119

127120
// Add a redirection to the new plugin settings, from the old plugin.
128-
if( is_admin() ) {
121+
if ( is_admin() ) {
129122
add_action( 'admin_menu', function () {
130123
global $plugin_page;
131124
if ( ! empty( $plugin_page ) && false !== strpos( $plugin_page, 'cloudinary-image-management-and-manipulation-in-the-cloud-cdn' ) ) {

cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/sync/class-delete-sync.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public function delete_asset( $post_id ) {
9595
}
9696
// Next we need to check that the file is in the cloudinary folder.
9797
$parts = explode( '/', $public_id );
98-
$cloudinary_folder = $this->plugin->config['settings']['general']['cloudinary_folder'];
98+
$cloudinary_folder = $this->plugin->config['settings']['sync_media']['cloudinary_folder'] ? $this->plugin->config['settings']['sync_media']['cloudinary_folder'] : '';
9999
if ( $cloudinary_folder === $parts[0] ) {
100100
$type = $this->plugin->components['sync']->managers['push']->get_resource_type( $post_id );
101101
$options = array(

cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/sync/class-download-sync.php

Lines changed: 79 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
namespace Cloudinary\Sync;
99

10+
use Cloudinary\Sync;
11+
1012
/**
1113
* Class Download_Sync.
1214
*
@@ -70,21 +72,16 @@ public function rest_endpoints( $endpoints ) {
7072
public function rest_can_upload_files( \WP_REST_Request $request ) {
7173

7274
// This would have been from an ajax call. Therefore verify based on capability.
73-
if ( is_user_logged_in() ) {
74-
return current_user_can( 'upload_files' );
75-
}
76-
77-
// If we get here, this is a background post, which will have a bg post nonce created.
78-
$nonce = $request->get_param( 'nonce' );
79-
80-
return wp_verify_nonce( $nonce, 'wp_rest' );
75+
return current_user_can( 'upload_files' );
8176
}
8277

8378
/**
84-
* Handle a failed download by deleting teh temp attachment and returning the error in json.
79+
* Handle a failed download by deleting the temp attachment and returning the error in json.
8580
*
8681
* @param int $attachment_id The attachment ID.
8782
* @param string $error The error text to return.
83+
*
84+
* @return \WP_Error
8885
*/
8986
public function handle_failed_download( $attachment_id, $error ) {
9087
// @todo: Place a handler to catch the error for logging.
@@ -109,6 +106,73 @@ public function rest_download_asset( \WP_REST_Request $request ) {
109106
$file_name = $request->get_param( 'filename' );
110107
$transformations = (array) $request->get_param( 'transformations' );
111108

109+
$response = $this->download_asset( $attachment_id, $file_path, $file_name, $transformations );
110+
if ( is_wp_error( $response ) ) {
111+
$this->handle_failed_download( $attachment_id, $response->get_error_message() );
112+
}
113+
114+
return rest_ensure_response( $response );
115+
}
116+
117+
/**
118+
* Prepare and sync down an asset stored remotely.
119+
*
120+
* @param $attachment_id
121+
*
122+
* @return array|\WP_Error
123+
*/
124+
public function down_sync( $attachment_id ) {
125+
$file = get_post_meta( $attachment_id, '_wp_attached_file', true );
126+
$path = wp_parse_url( $file, PHP_URL_PATH );
127+
$media = $this->plugin->components['media'];
128+
$parts = explode( '/', $path );
129+
$parts = array_map(
130+
function ( $val ) use ( $media ) {
131+
if ( empty( $val ) ) {
132+
return false;
133+
}
134+
if ( $val === $media->credentials['cloud_name'] ) {
135+
return false;
136+
}
137+
if ( in_array( $val, [ 'image', 'video', 'upload' ], true ) ) {
138+
return false;
139+
}
140+
$transformation_maybe = $media->get_transformations_from_string( $val );
141+
if ( ! empty( $transformation_maybe ) ) {
142+
return false;
143+
}
144+
if ( substr( $val, 0, 1 ) === 'v' && is_numeric( substr( $val, 1 ) ) ) {
145+
return false;
146+
}
147+
148+
return $val;
149+
},
150+
$parts
151+
);
152+
// Build public_id.
153+
$parts = array_filter( $parts );
154+
$public_id = implode( '/', $parts );
155+
// Remove extension.
156+
$path = pathinfo( $public_id );
157+
$public_id = strstr( $public_id, '.' . $path['extension'], true );
158+
// Save public ID.
159+
$media->update_post_meta( $attachment_id, Sync::META_KEYS['public_id'], $public_id );
160+
161+
return $this->download_asset( $attachment_id, $file, basename( $file ), $media->get_transformations_from_string( $file ) );
162+
}
163+
164+
/**
165+
* Download an attachment source to the file system.
166+
*
167+
* @param int $attachment_id The attachment ID.
168+
* @param string $file_path The path of the file.
169+
* @param string $file_name The filename.
170+
* @param array|null $transformations
171+
*
172+
* @return array|\WP_Error
173+
*/
174+
public function download_asset( $attachment_id, $file_path, $file_name, $transformations = null ) {
175+
112176
// Get the image and update the attachment.
113177
require_once ABSPATH . WPINC . '/class-http.php';
114178
require_once ABSPATH . 'wp-admin/includes/file.php';
@@ -120,8 +184,7 @@ public function rest_download_asset( \WP_REST_Request $request ) {
120184
// Prime a file to stream to.
121185
$upload = wp_upload_bits( $file_name, null, 'temp' );
122186
if ( ! empty( $upload['error'] ) ) {
123-
$this->handle_failed_download( $attachment_id, $upload['error'] );
124-
wp_send_json_error( $upload['error'] );
187+
return new \WP_Error( 'download_error', $upload['error'] );
125188
}
126189
// If the public_id of an asset includes a file extension, a derived item will have the extension duplicated, but not in the source URL.
127190
// This creates a 404. So, instead, we get the actual file name, and use that over the file name that the source url has.
@@ -137,7 +200,7 @@ public function rest_download_asset( \WP_REST_Request $request ) {
137200
);
138201

139202
if ( is_wp_error( $response ) ) {
140-
$this->handle_failed_download( $attachment_id, $response->get_error_message() );
203+
return $response;
141204
}
142205
if ( 200 !== $response['response']['code'] ) {
143206
$header_error = wp_remote_retrieve_header( $response, 'x-cld-error' );
@@ -146,7 +209,8 @@ public function rest_download_asset( \WP_REST_Request $request ) {
146209
} else {
147210
$error = __( 'Could not download the Cloudinary asset.', 'cloudinary' );
148211
}
149-
$this->handle_failed_download( $attachment_id, $error );
212+
213+
return new \WP_Error( 'download_error', $error );
150214
}
151215

152216
// Prepare the asset.
@@ -157,7 +221,7 @@ public function rest_download_asset( \WP_REST_Request $request ) {
157221
wp_update_attachment_metadata( $attachment_id, $meta );
158222

159223
} catch ( \Exception $e ) {
160-
$this->handle_failed_download( $attachment_id, $e->getMessage() );
224+
return new \WP_Error( 'download_error', $e->getMessage() );
161225
}
162226

163227
$attachment = wp_prepare_attachment_for_js( $attachment_id );
@@ -181,6 +245,6 @@ public function rest_download_asset( \WP_REST_Request $request ) {
181245
'data' => $attachment,
182246
);
183247

184-
return rest_ensure_response( $response );
248+
return $response;
185249
}
186250
}

cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/sync/class-push-sync.php

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ public function rest_push_attachments( \WP_REST_Request $request ) {
210210

211211
// Check if there is a Cloudinary ID in case this was synced on-demand before being processed by the queue.
212212
add_filter( 'cloudinary_on_demand_sync_enabled', '__return_false' ); // Disable the on-demand sync since we want the status.
213+
add_filter( 'cloudinary_id', '__return_false' ); // Disable the on-demand sync since we want the status.
213214
if ( false === $this->plugin->components['media']->cloudinary_id( $post_id ) ) {
214215
$stat = $this->push_attachments( array( $post_id ) );
215216
if ( ! empty( $stat['processed'] ) ) {
@@ -307,11 +308,12 @@ private function get_sync_type( $attachment ) {
307308
/**
308309
* Prepare an attachment for upload.
309310
*
310-
* @param int|\WP_Post $post The attachment to prepare.
311+
* @param int|\WP_Post $post The attachment to prepare.
312+
* @param bool $down_sync Flag to determine if a missing file starts a downsync.
311313
*
312314
* @return array|\WP_Error
313315
*/
314-
public function prepare_upload( $post ) {
316+
public function prepare_upload( $post, $down_sync = false ) {
315317

316318
if ( is_numeric( $post ) ) {
317319
$post = get_post( $post );
@@ -331,17 +333,36 @@ public function prepare_upload( $post ) {
331333
$file = get_attached_file( $post->ID );
332334
if ( empty( $file ) ) {
333335
return new \WP_Error( 'attachment_no_file', __( 'Attachment did not have a file.', 'cloudinary' ) );
336+
} elseif ( ! file_exists( $file ) ) {
337+
// May be an old upload type.
338+
$src = get_post_meta( $post->ID, '_wp_attached_file', true );
339+
if ( $this->plugin->components['media']->is_cloudinary_url( $src ) ) {
340+
// Download first maybe.
341+
if ( true === $down_sync ) {
342+
$download = $this->plugin->components['sync']->managers['download']->down_sync( $post->ID );
343+
if ( is_wp_error( $download ) ) {
344+
update_post_meta( $post->ID, Sync::META_KEYS['sync_error'], $download->get_error_message() );
345+
346+
return new \WP_Error( 'attachment_download_error', $download->get_error_message() );
347+
}
348+
$file = get_attached_file( $post->ID );
349+
$file_size = filesize( $file );
350+
} else {
351+
$file_size = 0;
352+
}
353+
}
354+
} else {
355+
$file_size = filesize( $file );
334356
}
335357

336-
$file_size = filesize( $file );
337358
$resource_type = $this->get_resource_type( $post );
338359
$max_size = ( 'image' === $resource_type ? 'max_image_size' : 'max_video_size' );
339360

340361
if ( $file_size > $this->plugin->components['connect']->usage[ $max_size ] ) {
341362
$max_size_hr = size_format( $this->plugin->components['connect']->usage[ $max_size ] );
342363
// translators: variable is file size.
343364
$error = sprintf( __( 'File size exceeds the maximum of %s. This media asset will be served from WordPress.', 'cloudinary' ), $max_size_hr );
344-
delete_post_meta( $post->ID, Sync::META_KEYS['pending'] ); // Remove Flag.
365+
$this->plugin->components['media']->delete_post_meta( $post->ID, Sync::META_KEYS['pending'] ); // Remove Flag.
345366

346367
return new \WP_Error( 'upload_error', $error );
347368
}
@@ -481,7 +502,7 @@ public function push_attachments( $attachments ) {
481502
// Go over each attachment.
482503
foreach ( $attachments as $attachment ) {
483504
$attachment = get_post( $attachment );
484-
$upload = $this->prepare_upload( $attachment->ID );
505+
$upload = $this->prepare_upload( $attachment->ID, true );
485506

486507
// Filter out any attachments with problematic options.
487508
if ( is_wp_error( $upload ) ) {
@@ -555,8 +576,8 @@ public function push_attachments( $attachments ) {
555576
if ( ! empty( $result['version'] ) ) {
556577
$meta_data[ Sync::META_KEYS['version'] ] = $result['version'];
557578
}
558-
delete_post_meta( $attachment->ID, Sync::META_KEYS['pending'] );
559-
$this->plugin->components['media']->update_post_meta( $attachment->ID, Sync::META_KEYS['sync_error'], false );
579+
$this->plugin->components['media']->delete_post_meta( $attachment->ID, Sync::META_KEYS['pending'] );
580+
$this->plugin->components['media']->delete_post_meta( $attachment->ID, Sync::META_KEYS['sync_error'], false );
560581
if ( ! empty( $this->plugin->config['settings']['global_transformations']['enable_breakpoints'] ) ) {
561582
if ( ! empty( $result['responsive_breakpoints'] ) ) { // Images only.
562583
$meta_data[ Sync::META_KEYS['breakpoints'] ] = $result['responsive_breakpoints'][0]['breakpoints'];
@@ -578,6 +599,7 @@ public function push_attachments( $attachments ) {
578599
$meta = wp_get_attachment_metadata( $attachment->ID, true );
579600
$meta[ Sync::META_KEYS['cloudinary'] ] = $meta_data;
580601
wp_update_attachment_metadata( $attachment->ID, $meta );
602+
$this->plugin->components['media']->update_post_meta( $attachment->ID, Sync::META_KEYS['public_id'], $upload['options']['public_id'] );
581603
// Search and update link references in content.
582604
$content_search = new \WP_Query( array( 's' => 'wp-image-' . $attachment->ID, 'fields' => 'ids', 'posts_per_page' => 1000 ) );
583605
if ( ! empty( $content_search->found_posts ) ) {

cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/sync/class-upload-queue.php

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -199,13 +199,6 @@ public function build_queue() {
199199
'key' => Sync::META_KEYS['public_id'],
200200
'compare' => 'NOT EXISTS',
201201
),
202-
array(
203-
'relation' => 'OR',
204-
array(
205-
'key' => Sync::META_KEYS['signature'],
206-
'compare' => 'NOT EXISTS',
207-
),
208-
),
209202
),
210203
'ignore_sticky_posts' => false,
211204
'no_found_rows' => true,

0 commit comments

Comments
 (0)