diff --git a/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/class-media.php b/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/class-media.php index 7cf4a4dde..4c8fac6b6 100644 --- a/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/class-media.php +++ b/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/class-media.php @@ -495,6 +495,7 @@ public function get_crop( $url, $attachment_id ) { // Make the WP Size array. $wp_size = array( 'wpsize' => $size_name, + 'file' => $size['file'], 'width' => $size['width'], 'height' => $size['height'], 'crop' => $cropped ? 'fill' : 'scale', @@ -604,9 +605,6 @@ public function get_transformations_from_string( $str, $type = 'image' ) { $transformation_chains = explode( '/', $str ); $transformations = array(); foreach ( $transformation_chains as $index => $chain ) { - if ( false !== strpos( $chain, 'wpsize' ) ) { - continue; // A wpsize is not a transformation. - } $items = explode( ',', $chain ); foreach ( $items as $item ) { $item = trim( $item ); @@ -724,7 +722,7 @@ public function apply_default_transformations( array $transformations, $type = ' * * @return string The converted URL. */ - public function cloudinary_url( $attachment_id, $size = array(), $transformations = array(), $cloudinary_id = null, $overwrite_transformations = false, $clean = false ) { + public function cloudinary_url( $attachment_id, $size = array(), $transformations = array(), $cloudinary_id = null, $overwrite_transformations = false ) { if ( ! ( $cloudinary_id ) ) { $cloudinary_id = $this->cloudinary_id( $attachment_id ); @@ -744,13 +742,7 @@ public function cloudinary_url( $attachment_id, $size = array(), $transformation 'resource_type' => $resource_type, ); - // Check size and correct if string or size. - if ( is_string( $size ) || ( is_array( $size ) && 3 === count( $size ) ) ) { - $intermediate = image_get_intermediate_size( $attachment_id, $size ); - if ( is_array( $intermediate ) ) { - $size = $this->get_crop( $intermediate['url'], $attachment_id ); - } - } + $size = $this->prepare_size( $attachment_id, $size ); if ( false === $overwrite_transformations ) { $overwrite_transformations = $this->maybe_overwrite_featured_image( $attachment_id ); } @@ -789,6 +781,44 @@ public function cloudinary_url( $attachment_id, $size = array(), $transformation return apply_filters( 'cloudinary_converted_url', $url, $attachment_id, $pre_args ); } + /** + * Prepare the Size array for the Cloudinary URL API. + * + * @param int $attachment_id The attachment ID. + * @param array|string $size The size array or slug. + * + * @return array|string + */ + public function prepare_size( $attachment_id, $size ) { + // Check size and correct if string or size. + if ( empty( $size ) || 'full' === $size ) { + // Maybe get full size if scaled. + $meta = wp_get_attachment_metadata( $attachment_id, true ); + if ( ! empty( $meta['original_image'] ) ) { + $size = array( + 'width' => $meta['width'], + 'height' => $meta['height'], + 'full' => true, + ); + } + } elseif ( is_string( $size ) || ( is_array( $size ) && 3 === count( $size ) ) ) { + $intermediate = image_get_intermediate_size( $attachment_id, $size ); + if ( is_array( $intermediate ) ) { + $size = $this->get_crop( $intermediate['url'], $attachment_id ); + } + } elseif ( array_keys( $size ) === array( 0, 1 ) ) { + $size = array( + 'width' => $size[0], + 'height' => $size[1], + ); + if ( $size['width'] === $size['height'] ) { + $size['crop'] = 'fill'; + } + } + + return $size; + } + /** * Add domain to subdir. * @@ -998,7 +1028,7 @@ public function convert_url( $url, $attachment_id, $transformations = array(), $ } $size = $this->get_crop( $url, $attachment_id ); - return $this->cloudinary_url( $attachment_id, $size, $transformations, null, $overwrite_transformations, true ); + return $this->cloudinary_url( $attachment_id, $size, $transformations, null, $overwrite_transformations ); } /** @@ -1017,8 +1047,8 @@ public function image_srcset( $sources, $size_array, $image_src, $image_meta, $a if ( ! $cloudinary_id ) { return $sources; // Return WordPress default sources. } - // Get transformations from URL. - $transformations = $this->get_transformations_from_string( $image_src ); + // Get transformations if any. + $transformations = $this->get_post_meta( $attachment_id, Sync::META_KEYS['transformation'], true ); // Use Cloudinary breakpoints for same ratio. if ( 'on' === $this->plugin->config['settings']['global_transformations']['enable_breakpoints'] && wp_image_matches_ratio( $image_meta['width'], $image_meta['height'], $size_array[0], $size_array[1] ) ) { @@ -1050,7 +1080,7 @@ function ( $item ) use ( $crop ) { 'width' => $breakpoint['width'], ); $sources[ $breakpoint['width'] ] = array( - 'url' => $this->cloudinary_url( $attachment_id, $size, $transformations, $cloudinary_id, true ), + 'url' => $this->cloudinary_url( $attachment_id, $size, $transformations, $cloudinary_id, $image_meta['overwrite_transformations'] ), 'descriptor' => 'w', 'value' => $breakpoint['width'], ); @@ -1076,35 +1106,13 @@ function ( $item ) use ( $crop ) { // Use current sources, but convert the URLS. foreach ( $sources as &$source ) { if ( ! $this->is_cloudinary_url( $source['url'] ) ) { - $source['url'] = $this->convert_url( $source['url'], $attachment_id, $transformations, true ); // Overwrite transformations applied, since the $transformations includes globals from the primary URL. + $source['url'] = $this->convert_url( $source['url'], $attachment_id, $transformations, $image_meta['overwrite_transformations'] ); // Overwrite transformations applied, since the $transformations includes globals from the primary URL. } } return $sources; } - /** - * Alter the image sizes metadata to match the Cloudinary ID so that WordPress can detect a matched source for responsive breakpoints. - * - * @param array $image_meta The image metadata array. - * @param array $size_array The size array. - * @param string $image_src The image src. - * @param int $attachment_id The attachment ID. - * - * @return array - */ - public function match_responsive_sources( $image_meta, $size_array, $image_src, $attachment_id ) { - if ( wp_attachment_is_image( $attachment_id ) && ! empty( $image_meta['sizes'] ) ) { - $cloudinary_id = $this->cloudinary_id( $attachment_id ); - if ( $cloudinary_id ) { - // Set the file to the Cloudinary ID so that it will be matched. - $image_meta['file'] = $cloudinary_id; - } - } - - return $image_meta; - } - /** * Check if a url is a cloudinary url or not. * @@ -1789,8 +1797,6 @@ public function setup() { // Filter live URLS. (functions that return a URL). add_filter( 'wp_calculate_image_srcset', array( $this, 'image_srcset' ), 10, 5 ); - add_filter( 'wp_calculate_image_srcset_meta', array( $this, 'match_responsive_sources' ), 10, 4 ); - add_filter( 'wp_get_attachment_metadata', array( $this, 'match_file_name_with_cloudinary_source' ), 10, 2 ); add_filter( 'wp_get_attachment_url', array( $this, 'attachment_url' ), 10, 2 ); add_filter( 'image_downsize', array( $this, 'filter_downsize' ), 10, 3 ); @@ -1802,23 +1808,4 @@ public function setup() { add_action( 'begin_fetch_post_thumbnail_html', array( $this, 'set_doing_featured' ), 10, 2 ); } } - - /** - * Ensure the file in image meta is the same as the Cloudinary ID. - * - * @param array $image_meta Meta information of the attachment. - * @param int $attachment_id The attachment ID. - * - * @return array - */ - public function match_file_name_with_cloudinary_source( $image_meta, $attachment_id ) { - if ( $this->has_public_id( $attachment_id ) ) { - $cld_file = 'v' . $this->get_cloudinary_version( $attachment_id ) . '/' . $this->get_cloudinary_id( $attachment_id ); - if ( false === strpos( $image_meta['file'], $cld_file ) ) { - $image_meta['file'] = $cld_file; - } - } - - return $image_meta; - } } diff --git a/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/class-sync.php b/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/class-sync.php index aafb13241..badb76417 100644 --- a/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/class-sync.php +++ b/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/class-sync.php @@ -286,7 +286,7 @@ public function get_signature( $attachment_id, $cached = true ) { public function generate_public_id( $attachment_id ) { $cld_folder = $this->managers['media']->get_cloudinary_folder(); - $file = get_attached_file( $attachment_id ); + $file = wp_get_original_image_path( $attachment_id ); $file_info = pathinfo( $file ); $public_id = $cld_folder . $file_info['filename']; diff --git a/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/connect/class-api.php b/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/connect/class-api.php index 2bee4bed6..bd6166060 100644 --- a/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/connect/class-api.php +++ b/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/connect/class-api.php @@ -96,7 +96,6 @@ class Api { 'pg' => 'page', 'sp' => 'streaming_profile', 'vs' => 'video_sampling', - '$wpsize' => 'wpsize', ), 'video' => array( 'w' => 'width', @@ -141,7 +140,7 @@ class Api { * @param string The plugin version. */ public function __construct( $connect, $version ) { - $this->credentials = $connect->get_credentials(); + $this->credentials = $connect->get_credentials(); $this->plugin_version = $version; // Use CNAME. if ( ! empty( $this->credentials['cname'] ) ) { @@ -172,8 +171,12 @@ public function url( $resource, $function = null, $endpoint = false ) { $parts[] = $this->credentials['cloud_name']; } - $parts[] = $resource; - $parts[] = $function; + if ( false === $endpoint && 'image' === $resource ) { + $parts[] = 'images'; + } else { + $parts[] = $resource; + $parts[] = $function; + } $parts = array_filter( $parts ); $url = implode( '/', $parts ); @@ -203,14 +206,6 @@ function ( $item ) use ( $transformation_index ) { foreach ( $item as $type => $value ) { // phpcs:ignore $key = array_search( $type, $transformation_index, true ); - if ( false !== strpos( $type, 'wpsize' ) ) { - if ( ! empty( $item['clean'] ) ) { - continue; - } - - $value = '!' . $value . '!'; - } - if ( false !== $key ) { $transform[] = $key . '_' . $value; } @@ -231,13 +226,12 @@ function ( $item ) use ( $transformation_index ) { * Generate a Cloudinary URL. * * @param string|null $public_id The Public ID to get a url for. - * @param array $args Additional args. - * @param array $size The WP Size array. - * @param bool $clean Flag to produce a non variable size url. + * @param array $args Additional args. + * @param array $size The WP Size array. * * @return string */ - public function cloudinary_url( $public_id = null, $args = array(), $size = array(), $clean = false ) { + public function cloudinary_url( $public_id = null, $args = array(), $size = array() ) { if ( null === $public_id ) { return 'https://' . $this->url( null, null ); @@ -267,22 +261,18 @@ public function cloudinary_url( $public_id = null, $args = array(), $size = arra if ( ! empty( $args['transformation'] ) ) { $url_parts[] = self::generate_transformation_string( $args['transformation'] ); } - + $base = pathinfo( $public_id ); + if ( 'image' === $args['resource_type'] ) { + $new_path = $base['filename'] . '/' . $base['basename']; + $public_id = str_replace( $base['basename'], $new_path, $public_id ); + } // Add size. if ( ! empty( $size ) && is_array( $size ) ) { - if ( true === $clean ) { - $size['clean'] = true; - } - if ( array_keys( $size ) == array( 0, 1 ) ) { - $size = array( - 'width' => $size[0], - 'height' => $size[1], - ); - if ( $size['width'] === $size['height'] ) { - $size['crop'] = 'fill'; - } - } $url_parts[] = self::generate_transformation_string( array( $size ) ); + // add size to ID if scaled. + if ( ! empty( $size['file'] ) ) { + $public_id = str_replace( $base['basename'], $size['file'], $public_id ); + } } $url_parts[] = $args['version']; @@ -418,7 +408,7 @@ public function upload( $attachment_id, $args, $headers = array() ) { $url = $this->url( $resource, 'upload', true ); $args = $this->clean_args( $args ); $disable_https_fetch = get_transient( '_cld_disable_http_upload' ); - $file_url = wp_get_attachment_url( $attachment_id ); + $file_url = wp_get_original_image_url( $attachment_id ); $media = get_plugin_instance()->get_component( 'media' ); if ( $media && $media->is_cloudinary_url( $file_url ) ) { // If this is a Cloudinary URL, then we can use it to fetch from that location. @@ -430,7 +420,7 @@ public function upload( $attachment_id, $args, $headers = array() ) { } else { // We should have the file in args at this point, but if the transient was set, it will be defaulting here. if ( empty( $args['file'] ) ) { - $args['file'] = get_attached_file( $attachment_id ); + $args['file'] = wp_get_original_image_path( $attachment_id ); } // Headers indicate chunked upload. if ( empty( $headers ) ) { @@ -466,7 +456,7 @@ public function upload( $attachment_id, $args, $headers = array() ) { // Hook in flag to allow for non accessible URLS. if ( is_wp_error( $result ) ) { $error = $result->get_error_message(); - $code = $result->get_error_code(); + $code = $result->get_error_code(); /** * If there's an error and the file is a URL in the error message, * it's likely due to CURL or the location does not support URL file attachments. diff --git a/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/media/class-filter.php b/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/media/class-filter.php index 93b39205e..0a9f6aaaa 100644 --- a/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/media/class-filter.php +++ b/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/media/class-filter.php @@ -266,13 +266,6 @@ public function filter_out_cloudinary( $data ) { if ( $this->media->is_cloudinary_url( $local_url ) ) { continue; } - $inherit_transformations = $this->media->get_transformation_from_meta( $attachment_id ); - $transformations = $this->media->get_transformations_from_string( $url ); - $transformations = array_filter( $transformations ); - if ( ! empty( $transformations ) && $inherit_transformations !== $transformations ) { - $transformations = Api::generate_transformation_string( $transformations ); - $local_url = add_query_arg( 'cld_params', $transformations, $local_url ); - } // Replace old tag. $content = str_replace( $url, $local_url, $content ); @@ -325,25 +318,20 @@ public function filter_out_local( $content ) { wp_parse_str( $query, $args ); $transformations = $this->media->get_transformations_from_string( $args['cld_params'] ); } - // Get the WP size from the class name. - $wp_size = $this->get_size_from_image_tag( $asset ); + $wp_size = $this->media->get_crop( $url, $attachment_id ); if ( false === $wp_size ) { // No class name, so get size from the width and height tags. $wp_size = $this->get_crop_from_image_tag( $asset ); - if ( empty( $wp_size ) ) { - $wp_size = 'full'; // Fallback to full if nothing is found at all. - } } // Get a cloudinary URL. - $clean = ! is_admin(); // Front facing images must not contain a wpsize url variable. $classes = $this->get_classes( $asset ); // check if this is a transformation overwrite. $overwrite_transformations = false; if ( false !== strpos( $classes, 'cld-overwrite' ) ) { $overwrite_transformations = true; } - $cloudinary_url = $this->media->cloudinary_url( $attachment_id, $wp_size, $transformations, null, $overwrite_transformations, $clean ); + $cloudinary_url = $this->media->cloudinary_url( $attachment_id, $wp_size, $transformations, null, $overwrite_transformations ); if ( $url === $cloudinary_url ) { continue; @@ -352,31 +340,32 @@ public function filter_out_local( $content ) { // Replace old tag. $new_tag = str_replace( $url, $cloudinary_url, $asset ); - // Check if there is a class set. ( for srcset images in case of a manual url added ). - if ( false === strpos( $new_tag, ' class=' ) && ! is_admin() ) { - // Add in the class name. - $new_tag = str_replace( '/>', ' class="wp-image-' . $attachment_id . '"/>', $new_tag ); - } - - // Apply lazy loading attribute - if ( - apply_filters( 'wp_lazy_loading_enabled', true ) && - false === strpos( $new_tag, 'loading="lazy"' ) && - $clean - ) { - $new_tag = str_replace( '/>', ' loading="lazy" />', $new_tag ); - } + // Add front end features. + if ( ! is_admin() ) { + // Check if there is a class set. ( for srcset images in case of a manual url added ). + if ( false === strpos( $new_tag, ' class=' ) ) { + // Add in the class name. + $new_tag = str_replace( '/>', ' class="wp-image-' . $attachment_id . '"/>', $new_tag ); + } + // Apply lazy loading attribute + if ( apply_filters( 'wp_lazy_loading_enabled', true ) && false === strpos( $new_tag, 'loading="lazy"' ) ) { + $new_tag = str_replace( '/>', ' loading="lazy" />', $new_tag ); + } - // If Cloudinary player is active, this is replaced there. - if ( ! $this->media->video->player_enabled() ) { - $poster = $this->get_poster_from_tag( $asset ); - if ( false !== $poster ) { - $post_attachment_id = $this->media->get_id_from_url( $poster ); - $cloudinary_url = $this->media->cloudinary_url( $post_attachment_id ); - $new_tag = str_replace( $poster, $cloudinary_url, $new_tag ); + // If Cloudinary player is active, this is replaced there. + if ( ! $this->media->video->player_enabled() ) { + $poster = $this->get_poster_from_tag( $asset ); + if ( false !== $poster ) { + $post_attachment_id = $this->media->get_id_from_url( $poster ); + $cloudinary_url = $this->media->cloudinary_url( $post_attachment_id ); + $new_tag = str_replace( $poster, $cloudinary_url, $new_tag ); + } } + $image_meta = wp_get_attachment_metadata( $attachment_id ); + $image_meta['file'] = pathinfo( $cloudinary_id, PATHINFO_FILENAME ) . '/' . pathinfo( $cloudinary_id, PATHINFO_BASENAME ); + $image_meta['overwrite_transformations'] = $overwrite_transformations; + $new_tag = wp_image_add_srcset_and_sizes( $new_tag, $image_meta, $attachment_id ); } - $content = str_replace( $asset, $new_tag, $content ); } @@ -712,7 +701,7 @@ public function setup_hooks() { // Filter URLS within content. add_action( 'wp_insert_post_data', array( $this, 'filter_out_cloudinary' ) ); add_filter( 'the_editor_content', array( $this, 'filter_out_local' ) ); - add_filter( 'the_content', array( $this, 'filter_out_local' ), 9 ); // Early to hook before responsive srcsets. + add_filter( 'the_content', array( $this, 'filter_out_local' ), 100 ); add_filter( 'wp_prepare_attachment_for_js', array( $this, 'filter_attachment_for_js' ), 11 ); // Add support for custom header. @@ -747,5 +736,15 @@ function ( $type ) use ( $filter ) { // Filter for block rendering. add_filter( 'render_block_data', array( $this, 'filter_image_block_pre_render' ), 10, 2 ); + + // Cancel out breakpoints till later. + add_filter( + 'wp_img_tag_add_srcset_and_sizes_attr', + function ( $add, $image, $context, $attachment_id ) { + return ! $this->media->has_public_id( $attachment_id ); + }, + 10, + 4 + ); } } diff --git a/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/sync/class-storage.php b/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/sync/class-storage.php index f2bb63527..4f5e2e4c0 100644 --- a/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/sync/class-storage.php +++ b/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/sync/class-storage.php @@ -181,13 +181,13 @@ public function sync( $attachment_id ) { // Add low quality transformations. $transformations[] = array( 'quality' => 'auto:low' ); } - $url = $this->media->cloudinary_url( $attachment_id, '', $transformations, null, false, true ); + $url = $this->media->cloudinary_url( $attachment_id, '', $transformations, null, false ); break; case 'dual_full': if ( ! empty( $previous_state ) && 'dual_full' !== $previous_state ) { // Only do this is it's changing a state. $transformations = $this->media->get_transformation_from_meta( $attachment_id ); - $url = $this->media->cloudinary_url( $attachment_id, '', $transformations, null, false, false ); + $url = $this->media->cloudinary_url( $attachment_id, '', $transformations, null, false ); } break; }