Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class Sync implements Setup, Assets {
'transformation' => '_transformations',
'sync_error' => '_sync_error',
'cloudinary' => '_cloudinary_v2',
'folder_sync' => '_folder_sync',
);

/**
Expand Down Expand Up @@ -100,8 +101,9 @@ public function is_active() {
*/
public function is_synced( $post_id ) {
$return = false;
$signature = $this->plugin->components['media']->get_post_meta( $post_id, self::META_KEYS['signature'], true );
if ( ! empty( $signature ) && $this->generate_signature( $post_id ) === $signature ) {
$signature = $this->get_signature( $post_id );
$expecting = $this->generate_signature( $post_id );
if ( ! empty( $signature ) && $expecting === $signature ) {
$return = $signature;
}

Expand Down Expand Up @@ -133,6 +135,31 @@ function ( $item ) {
return $return;
}

/**
* Get the current sync signature of an asset.
*
* @param int $post_id The post ID.
*
* @return array|bool
*/
public function get_signature( $post_id ) {
static $signatures = array(); // Cache signatures already fetched.

$return = false;
if ( ! empty( $signatures[ $post_id ] ) ) {
$return = $signatures[ $post_id ];
} else {
$signature = $this->plugin->components['media']->get_post_meta( $post_id, self::META_KEYS['signature'], true );
if ( ! empty( $signature ) ) {
$base_signatures = $this->generate_signature( $post_id );
$signatures[ $post_id ] = wp_parse_args( $signature, $base_signatures );
$return = $signatures[ $post_id ];
}
}

return $return;
}

/**
* Additional component setup.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ public function __construct( \Cloudinary\Media $media ) {
public function check_cloudinary_version( $cloudinary_id, $attachment_id ) {
if ( false === $cloudinary_id ) {
// Backwards compat.
$meta = wp_get_attachment_metadata( $attachment_id );
$meta = wp_get_attachment_metadata( $attachment_id );
if ( ! empty( $meta[ Sync::META_KEYS['cloudinary'] ] ) ) {
return $cloudinary_id; // Current version.
}
$public_id = $this->media->get_post_meta( $attachment_id, Sync::META_KEYS['public_id'], true );

/*
Expand All @@ -59,6 +62,24 @@ public function check_cloudinary_version( $cloudinary_id, $attachment_id ) {
// Has public ID, but not fully down synced.
$cloudinary_id = $public_id;
}
} else {
// Backwards compat.
$folder_sync = $this->media->get_post_meta( $attachment_id, Sync::META_KEYS['folder_sync'], true );
if ( 0 === strlen( $folder_sync ) ) {
// Does not exist, add it to be compatible with v1.2.2.
$public_id = $this->media->get_post_meta( $attachment_id, Sync::META_KEYS['public_id'], true );
// Set the folder sync to 0 to flag it by default as not synced.
$this->media->update_post_meta( $attachment_id, Sync::META_KEYS['folder_sync'], '0' );
if ( false !== strpos( $public_id, '/' ) ) {
$path = pathinfo( $public_id );
$asset_folder = trailingslashit( $path['dirname'] );
$cloudinary_folder = trailingslashit( $this->media->plugin->config['settings']['sync_media']['cloudinary_folder'] );
if ( $asset_folder === $cloudinary_folder ) {
// The asset folder matches the defined cloudinary folder, flag it as being in a folder sync.
$this->media->update_post_meta( $attachment_id, Sync::META_KEYS['folder_sync'], '1' );
}
}
}
}

return $cloudinary_id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,16 @@ function ( $val ) use ( $media ) {
$public_id = strstr( $public_id, '.' . $path['extension'], true );
// Save public ID.
$media->update_post_meta( $attachment_id, Sync::META_KEYS['public_id'], $public_id );
// Check if the asset is in the same folder as the defined Cloudinary folder.
if ( false !== strpos( $public_id, '/' ) ) {
$path = pathinfo( $public_id );
$asset_folder = trailingslashit( $path['dirname'] );
$cloudinary_folder = trailingslashit( $this->plugin->config['settings']['sync_media']['cloudinary_folder'] );
if ( $asset_folder === $cloudinary_folder ) {
// The asset folder matches the defined cloudinary folder, flag it as being in a folder sync.
$media->update_post_meta( $attachment_id, Sync::META_KEYS['folder_sync'], true );
}
}

return $this->download_asset( $attachment_id, $file, basename( $file ), $media->get_transformations_from_string( $file ) );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,12 @@ public function __construct( \Cloudinary\Plugin $plugin ) {

// Define the sync types and their option keys.
$sync_types = array(
'cloud_name' => 'upload',
'folder' => 'upload',
'file' => 'upload',
'public_id' => 'rename',
'breakpoints' => 'explicit',
'options' => 'context',
'folder' => 'upload',
'cloud_name' => 'upload',
);
$this->sync_types = apply_filters( 'cloudinary_sync_types', $sync_types );

Expand Down Expand Up @@ -303,15 +304,15 @@ private function get_sync_type( $attachment ) {

$type = 'upload';
// Check for explicit (has public_id, but no breakpoints).
$attachment_signature = $attachment->{Sync::META_KEYS['signature']};
$attachment_signature = $this->plugin->components['sync']->get_signature( $attachment->ID );
if ( empty( $attachment_signature ) ) {
if ( ! empty( $attachment->{Sync::META_KEYS['public_id']} ) ) {
// Has a public id but no signature, explicit update to complete download.
$type = 'explicit';
}
// fallback to upload.
} else {
// Has signature. Compare and find if different.
// Has signature find differences and use specific sync method.
$required_signature = $this->plugin->components['sync']->generate_signature( $attachment->ID );
foreach ( $required_signature as $key => $signature ) {
if ( ( ! isset( $attachment_signature[ $key ] ) || $attachment_signature[ $key ] !== $signature ) && isset( $this->sync_types[ $key ] ) ) {
Expand Down Expand Up @@ -350,6 +351,9 @@ public function prepare_upload( $post, $down_sync = false ) {
return new \WP_Error( 'attachment_post_expected', __( 'An attachment post was expected.', 'cloudinary' ) );
}

// Get the media component.
$media = $this->plugin->components['media'];

// First check if this has a file and it can be uploaded.
$file = get_attached_file( $post->ID );
$file_size = 0;
Expand All @@ -358,7 +362,7 @@ public function prepare_upload( $post, $down_sync = false ) {
} elseif ( ! file_exists( $file ) ) {
// May be an old upload type.
$src = get_post_meta( $post->ID, '_wp_attached_file', true );
if ( $this->plugin->components['media']->is_cloudinary_url( $src ) ) {
if ( $media->is_cloudinary_url( $src ) ) {
// Download first maybe.
if ( true === $down_sync ) {
$download = $this->plugin->components['sync']->managers['download']->down_sync( $post->ID );
Expand All @@ -383,36 +387,44 @@ public function prepare_upload( $post, $down_sync = false ) {

// translators: variable is file size.
$error = sprintf( __( 'File size exceeds the maximum of %s. This media asset will be served from WordPress.', 'cloudinary' ), $max_size_hr );
$this->plugin->components['media']->delete_post_meta( $post->ID, Sync::META_KEYS['pending'] ); // Remove Flag.
$media->delete_post_meta( $post->ID, Sync::META_KEYS['pending'] ); // Remove Flag.

return new \WP_Error( 'upload_error', $error );
}

// If it's got a public ID, then this is an explicit update.
$settings = $this->plugin->config['settings'];
$public_id = $post->{Sync::META_KEYS['public_id']}; // use the __get method on the \WP_Post to get post_meta.
$dirs = wp_get_upload_dir();
$cld_folder = false;
$folder = trailingslashit( $dirs['cloudinary_folder'] );
if ( '/' === $dirs['cloudinary_folder'] ) {
$folder = '';
}
$cld_folder = trailingslashit( $settings['sync_media']['cloudinary_folder'] );
if ( empty( $public_id ) ) {
$file_info = pathinfo( $file );
$public_id = $folder . $file_info['filename'];
}

// Check if cloudinary folder is in public_id.
$parts = explode( '/', $public_id );
if ( untrailingslashit( $dirs['cloudinary_folder'] ) === $parts[0] ) {
$cld_folder = $dirs['cloudinary_folder'];
$public_id = $cld_folder . $file_info['filename'];
}

// Assume that the public_id is a root item.
$public_id_folder = '';
$public_id_file = $public_id;

// Check if in a lower level.
if ( false !== strpos( $public_id, '/' ) ) {
// Split the public_id into path and filename to allow filtering just the ID and not giving access to the path.
$public_id_info = pathinfo( $public_id );
$public_id_folder = trailingslashit( $public_id_info['dirname'] );
$public_id_file = $public_id_info['filename'];
}
// Check if this asset is a folder sync.
$folder_sync = $media->get_post_meta( $post->ID, Sync::META_KEYS['folder_sync'], true );
if ( ! empty( $folder_sync ) ) {
$public_id_folder = $cld_folder; // Ensure the public ID folder is constant.
} else {
// Not folder synced, so set the folder to the folder that the asset originally came from.
$cld_folder = $public_id_folder;
}
// Prepare upload options.
$options = array(
'unique_filename' => false,
'resource_type' => $resource_type,
'public_id' => $public_id,
'public_id' => $public_id_file,
'context' => array(
'caption' => esc_attr( $post->post_title ),
'alt' => $post->_wp_attachment_image_alt,
Expand All @@ -434,17 +446,17 @@ public function prepare_upload( $post, $down_sync = false ) {
$imagesize = getimagesize( $file );
$meta['width'] = $imagesize[0];
}
$max_width = $this->plugin->components['media']->get_max_width();
$max_width = $media->get_max_width();
// Add breakpoints request options.
if ( ! empty( $this->plugin->config['settings']['global_transformations']['enable_breakpoints'] ) ) {
if ( ! empty( $settings['global_transformations']['enable_breakpoints'] ) ) {
$options['responsive_breakpoints'] = array(
'create_derived' => true,
'bytes_step' => $this->plugin->config['settings']['global_transformations']['bytes_step'],
'max_images' => $this->plugin->config['settings']['global_transformations']['breakpoints'],
'bytes_step' => $settings['global_transformations']['bytes_step'],
'max_images' => $settings['global_transformations']['breakpoints'],
'max_width' => $meta['width'] < $max_width ? $meta['width'] : $max_width,
'min_width' => $this->plugin->config['settings']['global_transformations']['min_width'],
'min_width' => $settings['global_transformations']['min_width'],
);
$transformations = $this->plugin->components['media']->get_transformation_from_meta( $post->ID );
$transformations = $media->get_transformation_from_meta( $post->ID );
if ( ! empty( $transformations ) ) {
$options['responsive_breakpoints']['transformation'] = Api::generate_transformation_string( $transformations );
}
Expand Down Expand Up @@ -474,14 +486,19 @@ public function prepare_upload( $post, $down_sync = false ) {
$breakpoints['context'] = http_build_query( $breakpoints['context'], null, '|' );
}

$return = array(
// Restructure the path to the filename to allow correct placement in Cloudinary.
$public_id = $public_id_folder . $options['public_id'];
$return = array(
'file' => $file,
'folder' => $cld_folder,
'public_id' => $public_id,
'breakpoints' => array(),
'options' => $options,
);
$return['options']['public_id'] = $public_id;
if ( ! empty( $breakpoints ) ) {
$return['breakpoints'] = $breakpoints;
$return['breakpoints'] = $breakpoints;
$return['breakpoints']['public_id'] = $public_id; // Stage public ID to folder for breakpoints.
}
$this->upload_options[ $post->ID ] = $return;

Expand Down Expand Up @@ -519,6 +536,8 @@ public function push_attachments( $attachments ) {
'total' => count( $attachments ),
'processed' => 0,
);
// Get media component.
$media = $this->plugin->components['media'];

// Go over each attachment.
foreach ( $attachments as $attachment ) {
Expand Down Expand Up @@ -560,7 +579,7 @@ public function push_attachments( $attachments ) {
if ( 'explicit' === $sync_type ) {
// Explicit update.
$args = array(
'public_id' => $upload['options']['public_id'],
'public_id' => $upload['public_id'],
'type' => 'upload',
);
if ( ! empty( $upload['options']['responsive_breakpoints'] ) ) {
Expand All @@ -570,6 +589,13 @@ public function push_attachments( $attachments ) {
$args['context'] = $upload['options']['context'];
}
$result = $this->plugin->components['connect']->api->explicit( $args );
} elseif ( 'rename' === $sync_type ) {
// Rename an asset.
$args = array(
'from_public_id' => $media->get_post_meta( $attachment->ID, Sync::META_KEYS['public_id'] ),
'to_public_id' => $upload['public_id'],
);
$result = $this->plugin->components['connect']->api->{$upload['options']['resource_type']}( 'rename', 'POST', $args );
} else {
// dynamic sync type..
$result = $this->plugin->components['connect']->api->{$sync_type}( $upload['file'], $upload['options'] );
Expand All @@ -583,7 +609,7 @@ public function push_attachments( $attachments ) {
if ( is_wp_error( $result ) ) {
$error = $result->get_error_message();
$stats['fail'][] = $error;
$this->plugin->components['media']->update_post_meta( $attachment->ID, Sync::META_KEYS['sync_error'], $error );
$media->update_post_meta( $attachment->ID, Sync::META_KEYS['sync_error'], $error );
continue;
}

Expand All @@ -597,8 +623,8 @@ public function push_attachments( $attachments ) {
if ( ! empty( $result['version'] ) ) {
$meta_data[ Sync::META_KEYS['version'] ] = $result['version'];
}
$this->plugin->components['media']->delete_post_meta( $attachment->ID, Sync::META_KEYS['pending'] );
$this->plugin->components['media']->delete_post_meta( $attachment->ID, Sync::META_KEYS['sync_error'], false );
$media->delete_post_meta( $attachment->ID, Sync::META_KEYS['pending'] );
$media->delete_post_meta( $attachment->ID, Sync::META_KEYS['sync_error'], false );
if ( ! empty( $this->plugin->config['settings']['global_transformations']['enable_breakpoints'] ) ) {
if ( ! empty( $result['responsive_breakpoints'] ) ) { // Images only.
$meta_data[ Sync::META_KEYS['breakpoints'] ] = $result['responsive_breakpoints'][0]['breakpoints'];
Expand All @@ -619,7 +645,7 @@ public function push_attachments( $attachments ) {
$meta = wp_get_attachment_metadata( $attachment->ID, true );
$meta[ Sync::META_KEYS['cloudinary'] ] = $meta_data;
wp_update_attachment_metadata( $attachment->ID, $meta );
$this->plugin->components['media']->update_post_meta( $attachment->ID, Sync::META_KEYS['public_id'], $upload['options']['public_id'] );
$media->update_post_meta( $attachment->ID, Sync::META_KEYS['public_id'], $upload['options']['public_id'] );
// Search and update link references in content.
$content_search = new \WP_Query( array( 's' => 'wp-image-' . $attachment->ID, 'fields' => 'ids', 'posts_per_page' => 1000 ) );
if ( ! empty( $content_search->found_posts ) ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ public function add_to_sync( $attachment_id ) {
if ( ! in_array( $attachment_id, $this->to_sync, true ) ) {
// Flag image as pending to prevent duplicate upload.
update_post_meta( $attachment_id, Sync::META_KEYS['pending'], time() );
$this->plugin->components['media']->update_post_meta( $attachment_id, Sync::META_KEYS['folder_sync'], true );
$this->to_sync[] = $attachment_id;
}
}
Expand Down