cloudinary://API_Key:API_Secret@Cloud_Name'
+ 'cloudinary://API_KEY:API_SECRET@CLOUD_NAME'
);
return $result;
@@ -198,11 +234,14 @@ function ( $a ) {
}
$this->config_from_url( $url );
- $test = new Connect\Api( $this, $this->plugin->version );
- $test = $test->ping();
- if ( is_wp_error( $test ) ) {
+ $test = new Connect\Api( $this, $this->plugin->version );
+ $test_result = $test->ping();
+ if ( is_wp_error( $test_result ) ) {
$result['type'] = 'connection_error';
- $result['message'] = ucwords( str_replace( '_', ' ', $test->get_error_message() ) );
+ $result['message'] = ucwords( str_replace( '_', ' ', $test_result->get_error_message() ) );
+ } else {
+ $this->api = $test;
+ $this->usage_stats( true );
}
return $result;
@@ -274,23 +313,62 @@ public function setup() {
// Get the cloudinary url from plugin config.
$config = $this->plugin->config['settings']['connect'];
if ( ! empty( $config['cloudinary_url'] ) ) {
-
$this->config_from_url( $config['cloudinary_url'] );
-
$this->api = new Connect\Api( $this, $this->plugin->version );
- $stats = get_transient( '_cloudinary_usage' );
- if ( empty( $stats ) ) {
- // Get users plan.
- $stats = $this->plugin->components['connect']->api->usage();
- if ( ! is_wp_error( $stats ) && ! empty( $stats['media_limits'] ) ) {
- $stats['max_image_size'] = $stats['media_limits']['image_max_size_bytes'];
- $stats['max_video_size'] = $stats['media_limits']['video_max_size_bytes'];
- set_transient( '_cloudinary_usage', $stats, HOUR_IN_SECONDS );
- }
+ $this->usage_stats();
+ }
+ }
+
+ /**
+ * Set the usage stats from the Cloudinary API.
+ *
+ * @param bool $refresh Flag to force a refresh.
+ */
+ public function usage_stats( $refresh = false ) {
+ $stats = get_transient( self::META_KEYS['usage'] );
+ if ( empty( $stats ) || true === $refresh ) {
+ // Get users plan.
+ $stats = $this->api->usage();
+ if ( ! is_wp_error( $stats ) && ! empty( $stats['media_limits'] ) ) {
+ $stats['max_image_size'] = $stats['media_limits']['image_max_size_bytes'];
+ $stats['max_video_size'] = $stats['media_limits']['video_max_size_bytes'];
+ set_transient( self::META_KEYS['usage'], $stats, HOUR_IN_SECONDS );
+ update_option( self::META_KEYS['last_usage'], $stats );// Save the last successful call to prevent crashing.
+ } else {
+ // Handle error by logging and fetching the last success.
+ // @todo : log issue.
+ $stats = get_option( self::META_KEYS['last_usage'] );
}
- $this->usage = $stats;
+ }
+ $this->usage = $stats;
+ }
+ /**
+ * Get a usage stat for display.
+ *
+ * @param string $type The type of stat to get.
+ * @param string|null $stat The stat to get.
+ *
+ * @return bool|string
+ */
+ public function get_usage_stat( $type, $stat = null ) {
+ $value = false;
+ if ( isset( $this->usage[ $type ] ) ) {
+ if ( is_string( $this->usage[ $type ] ) ) {
+ $value = $this->usage[ $type ];
+ } elseif ( is_array( $this->usage[ $type ] ) && isset( $this->usage[ $type ][ $stat ] ) ) {
+ $value = $this->usage[ $type ][ $stat ];
+ } elseif ( is_array( $this->usage[ $type ] ) ) {
+
+ if ( 'limit' === $stat && isset( $this->usage[ $type ]['usage'] ) ) {
+ $value = $this->usage[ $type ]['usage'];
+ } elseif ( 'used_percent' === $stat && isset( $this->usage[ $type ]['credits_usage'] ) ) {
+ $value = $this->usage[ $type ]['credits_usage'];
+ }
+ }
}
+
+ return $value;
}
/**
@@ -301,42 +379,115 @@ public function setup() {
* @return array The array of the config options stored.
*/
public function get_config() {
- $signature = get_option( 'cloudinary_connection_signature', null );
- if ( empty( $signature ) ) {
- // Check if theres a previous version.
- $version = get_option( 'cloudinary_version' );
- if ( version_compare( $this->plugin->version, $version, '>' ) ) {
+ $signature = get_option( self::META_KEYS['signature'], null );
+ $version = get_option( self::META_KEYS['version'] );
+ if ( empty( $signature ) || version_compare( $this->plugin->version, $version, '>' ) ) {
+ // Check if there's a previous version, or missing signature.
+ $cld_url = get_option( self::META_KEYS['url'], null );
+ if ( null === $cld_url ) {
+ // Post V1.
+ $data = get_option( self::META_KEYS['connect'], array() );
+ if ( ! isset( $data['cloudinary_url'] ) || empty( $data['cloudinary_url'] ) ) {
+ return null; // return null to indicate not valid.
+ }
+ } else {
+ // from V1 to V2.
$data = array(
- 'cloudinary_url' => get_option( 'cloudinary_url' ),
+ 'cloudinary_url' => $cld_url,
);
- $test = $this->test_connection( $data['cloudinary_url'] );
- if ( 'connection_success' === $test['type'] ) {
- $signature = md5( $data['cloudinary_url'] );
-
- // remove filters as we've already verified it and 'add_settings_error()' isin't available yet.
- remove_filter( 'pre_update_option_cloudinary_connect', array( $this, 'verify_connection' ) );
- update_option( 'cloudinary_connect', $data );
- update_option( 'cloudinary_connection_signature', $signature );
- update_option( 'cloudinary_version', $this->plugin->version );
- delete_option( 'cloudinary_settings_cache' ); // remove the cache.
- $this->plugin->config['settings']['connect'] = $data; // Set the connection url for this round.
+ // Set auto sync off.
+ $sync = get_option( 'cloudinary_sync_media' );
+ if ( empty( $sync ) ) {
+ $sync = array(
+ 'auto_sync' => '',
+ 'cloudinary_folder' => '',
+ );
}
+ $sync['auto_sync'] = 'off';
+ update_option( 'cloudinary_sync_media', $sync );
+ delete_option( 'cloudinary_settings_cache' ); // remove the cache.
+ }
+
+ $data['cloudinary_url'] = str_replace( 'CLOUDINARY_URL=', '', $data['cloudinary_url'] );
+ $test = $this->test_connection( $data['cloudinary_url'] );
+
+ if ( 'connection_success' === $test['type'] ) {
+ $signature = md5( $data['cloudinary_url'] );
+
+ // remove filters as we've already verified it and 'add_settings_error()' isin't available yet.
+ remove_filter( 'pre_update_option_cloudinary_connect', array( $this, 'verify_connection' ) );
+ update_option( self::META_KEYS['connect'], $data );
+ update_option( self::META_KEYS['signature'], $signature );
+ update_option( self::META_KEYS['version'], $this->plugin->version );
+ delete_option( self::META_KEYS['cache'] ); // remove the cache.
+ $this->plugin->config['settings']['connect'] = $data; // Set the connection url for this round.
}
}
return $signature;
}
+ /**
+ * Set usage notices if limits are towards higher end.
+ */
+ public function usage_notices() {
+ if ( ! empty( $this->usage ) ) {
+ $usage_type = 'used_percent';
+ if ( isset( $this->usage['credits'] ) ) {
+ $usage_type = 'credits_usage';
+ }
+ foreach ( $this->usage as $stat => $values ) {
+
+ if ( ! is_array( $values ) || ! isset( $values[ $usage_type ] ) || 0 > $values[ $usage_type ] ) {
+ continue;
+ }
+
+ $link = null;
+ $link_text = null;
+ if ( 90 <= $values[ $usage_type ] ) {
+ // 90% used - show error.
+ $level = 'error';
+ $link = 'https://cloudinary.com/console/lui/upgrade_options';
+ $link_text = __( 'upgrade your account', 'cloudinary' );
+ } elseif ( 80 <= $values[ $usage_type ] ) {
+ $level = 'warning';
+ $link_text = __( 'upgrade your account', 'cloudinary' );
+ } elseif ( 70 <= $values[ $usage_type ] ) {
+ $level = 'neutral';
+ $link_text = __( 'upgrade your account', 'cloudinary' );
+ } else {
+ continue;
+ }
+ // translators: Placeholders are URLS and percentage values.
+ $message = sprintf(
+ __(
+ ' You are %2$s of the way through your monthly quota for %1$s on your Cloudinary account. If you exceed your quota, the Cloudinary plugin will be deactivated until your next billing cycle and your media assets will be served from your WordPress Media Library. You may wish to %4$s and increase your quota to ensure you maintain full functionality.',
+ 'cloudinary'
+ ),
+ ucwords( $stat ),
+ $values[ $usage_type ] . '%',
+ $link,
+ $link_text
+ );
+ $this->notices[] = array(
+ 'message' => $message,
+ 'type' => $level,
+ 'dismissible' => false,
+ );
+ }
+ }
+ }
+
/**
* Get admin notices.
*/
public function get_notices() {
- $screen = get_current_screen();
- $notices = array();
+ $this->usage_notices();
+ $screen = get_current_screen();
if ( empty( $this->plugin->config['connect'] ) ) {
if ( is_object( $screen ) && in_array( $screen->id, $this->plugin->components['settings']->handles, true ) ) {
- $link = '' . __( 'Connect', 'cloudinary' ) . ' ';
- $notices[] = array(
+ $link = '' . __( 'Connect', 'cloudinary' ) . ' ';
+ $this->notices[] = array(
'message' => $link . __( 'your Cloudinary account with WordPress to get started.', 'cloudinary' ),
'type' => 'error',
'dismissible' => true,
@@ -344,7 +495,7 @@ public function get_notices() {
}
}
- return $notices;
+ return $this->notices;
}
}
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 cd966dc35..56b38edf2 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
@@ -463,7 +463,7 @@ public function get_transformations_from_string( $str, $type = 'image' ) {
* @return string Cloudinary URL.
*/
public function attachment_url( $url, $attachment_id ) {
- if ( ! doing_action( 'wp_insert_post_data' ) && wp_attachment_is( 'video', $attachment_id ) ) {
+ if ( ! doing_action( 'wp_insert_post_data' ) && ! is_admin() ) {
$cloudinary_id = $this->cloudinary_id( $attachment_id );
if ( false !== $cloudinary_id ) {
$url = $this->cloudinary_url( $attachment_id, $cloudinary_id );
@@ -542,16 +542,16 @@ public function apply_default_transformations( array $transformations, $type = '
/**
* Generate a Cloudinary URL based on attachment ID and required size.
*
- * @param int $attachment_id The id of the attachment.
- * @param array|string $size The wp size to set for the URL.
- * @param array $transformations Set of transformations to apply to this url.
- * @param string $cloudinary_id Optional forced cloudinary ID.
- * @param bool $breakpoint Flag url is a breakpoint URL to stop re-applying default transformations.
- * @param bool $clean Flag to present a clean url (With out a WP size variable.
+ * @param int $attachment_id The id of the attachment.
+ * @param array|string $size The wp size to set for the URL.
+ * @param array $transformations Set of transformations to apply to this url.
+ * @param string $cloudinary_id Optional forced cloudinary ID.
+ * @param bool $overwrite_transformations Flag url is a breakpoint URL to stop re-applying default transformations.
+ * @param bool $clean Flag to present a clean url (With out a WP size variable.
*
* @return string The converted URL.
*/
- public function cloudinary_url( $attachment_id, $size = array(), $transformations = array(), $cloudinary_id = null, $breakpoint = false, $clean = false ) {
+ public function cloudinary_url( $attachment_id, $size = array(), $transformations = array(), $cloudinary_id = null, $overwrite_transformations = false, $clean = false ) {
if ( empty( $cloudinary_id ) ) {
$cloudinary_id = $this->cloudinary_id( $attachment_id );
@@ -574,7 +574,9 @@ public function cloudinary_url( $attachment_id, $size = array(), $transformation
// 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 );
- $size = $this->get_crop( $intermediate['url'], $attachment_id );
+ if ( is_array( $intermediate ) ) {
+ $size = $this->get_crop( $intermediate['url'], $attachment_id );
+ }
}
/**
@@ -587,7 +589,7 @@ public function cloudinary_url( $attachment_id, $size = array(), $transformation
*/
$pre_args['transformation'] = apply_filters( 'cloudinary_transformations', $transformations, $attachment_id );
// Defaults are only to be added on front, main images ( not breakpoints, since these are adapted down), and videos.
- if ( ( ! defined( 'REST_REQUEST' ) || false === REST_REQUEST ) && ! is_admin() && false === $breakpoint ) {
+ if ( ( ! defined( 'REST_REQUEST' ) || false === REST_REQUEST ) && ! is_admin() && false === $overwrite_transformations ) {
$pre_args['transformation'] = $this->apply_default_transformations( $pre_args['transformation'], $resource_type );
}
@@ -732,17 +734,21 @@ public function filter_downsize( $image, $attachment_id, $size ) {
/**
* Convert an attachment URL to a Cloudinary one.
*
- * @param string $url Url to convert.
- * @param int $attachment_id Attachment ID.
- * @param array $transformations Optional transformations.
+ * @param string $url Url to convert.
+ * @param int $attachment_id Attachment ID.
+ * @param array $transformations Optional transformations.
+ * @param bool $overwrite_transformations Flag url as having an overwrite transformation.
*
* @return string Converted URL.
*/
- public function convert_url( $url, $attachment_id, $transformations = array() ) {
+ public function convert_url( $url, $attachment_id, $transformations = array(), $overwrite_transformations = true ) {
+ if ( $this->is_cloudinary_url( $url ) ) {
+ return $url; // Already is a cloudinary URL, just return.
+ }
$size = $this->get_crop( $url, $attachment_id );
- return $this->cloudinary_url( $attachment_id, $size, $transformations, null, true );
+ return $this->cloudinary_url( $attachment_id, $size, $transformations, null, $overwrite_transformations, true );
}
/**
@@ -820,7 +826,7 @@ 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 );
+ $source['url'] = $this->convert_url( $source['url'], $attachment_id, $transformations, true ); // Overwrite transformations applied, since the $transformations includes globals from the primary URL.
}
}
@@ -1006,7 +1012,7 @@ public function down_sync_asset() {
}
$transformations = $this->get_transformations_from_string( $url );
if ( ! empty( $transformations ) ) {
- $sync_key .= wp_json_encode( $transformations );
+ $sync_key .= wp_json_encode( $transformations );
$asset['transformations'] = $transformations;
}
// Check Format and url extension.
@@ -1072,19 +1078,24 @@ public function media_column_value( $column_name, $attachment_id ) {
if ( 'cld_status' === $column_name ) {
if ( $this->is_media( $attachment_id ) ) {
$status = array(
- 'state' => 'success',
- 'note' => esc_html__( 'Synced', 'cloudinary' ),
+ 'state' => 'inactive',
+ 'note' => esc_html__( 'Not Synced', 'cloudinary' ),
);
if ( false === $this->cloudinary_id( $attachment_id ) ) {
// If false, lets check why by seeing if the file size is too large.
$file = get_attached_file( $attachment_id ); // Get the file size to make sure it can exist in cloudinary.
- $max_size = ( wp_attachment_is_image( $attachment_id ) ? 'max_image_size' : 'max_video_size' );
- if ( file_exists( $file ) && filesize( $file ) > $this->plugin->components['connect']->usage[ $max_size ] ) {
- $max_size_hr = size_format( $this->plugin->components['connect']->usage[ $max_size ] );
+ $max_size = ( wp_attachment_is_image( $attachment_id ) ? 'image_max_size_bytes' : 'video_max_size_bytes' );
+ if ( file_exists( $file ) && filesize( $file ) > $this->plugin->components['connect']->usage['media_limits'][ $max_size ] ) {
+ $max_size_hr = size_format( $this->plugin->components['connect']->usage['media_limits'][ $max_size ] );
// translators: variable is file size.
$status['note'] = sprintf( __( 'File size exceeds the maximum of %s. This media asset will be served from WordPress.', 'cloudinary' ), $max_size_hr );
$status['state'] = 'error';
}
+ } else {
+ $status = array(
+ 'state' => 'success',
+ 'note' => esc_html__( 'Synced', 'cloudinary' ),
+ );
}
// filter status.
$status = apply_filters( 'cloudinary_media_status', $status, $attachment_id );
@@ -1252,9 +1263,9 @@ public function build_cached_meta( $post_id, $key, $single ) {
/**
* Update cloudinary metadata.
*
- * @param int $post_id The attachment ID.
- * @param string $key The meta key to get.
- * @param array $data $the meta data to update.
+ * @param int $post_id The attachment ID.
+ * @param string $key The meta key to get.
+ * @param string|array $data $the meta data to update.
*/
public function update_post_meta( $post_id, $key, $data ) {
$meta_data = wp_get_attachment_metadata( $post_id, true );
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 bad5c3d94..75c0bbb27 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
@@ -186,6 +186,9 @@ public static function generate_transformation_string( array $options, $type = '
$transformations = array_map(
function ( $item ) use ( $transformation_index ) {
$transform = array();
+ if ( is_string ( $item ) ) {
+ return $item;
+ }
foreach ( $item as $type => $value ) { // phpcs:ignore
$key = array_search( $type, $transformation_index, true );
if ( 'wpsize' === $type ) {
@@ -241,7 +244,7 @@ public function cloudinary_url( $public_id, $args = array(), $size = array(), $c
$url_parts[] = self::generate_transformation_string( $args['transformation'] );
}
// Add size.
- if ( ! empty( $size ) ) {
+ if ( ! empty( $size ) && is_array( $size ) ) {
if ( true === $clean ) {
$size['clean'] = true;
}
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 5c2b0890a..553b4117a 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
@@ -671,6 +671,45 @@ public function filter_image_block_pre_render( $block, $source_block ) {
return $block;
}
+ /**
+ * Attempt to set the width and height for SVGs.
+ *
+ * @param array|false $image The image details.
+ * @param int $attachment_id The attachment ID.
+ * @param string|int[] $size The requested image size.
+ *
+ * @return array|false
+ */
+ public function filter_svg_image_size( $image, $attachment_id, $size ) {
+ if ( is_array( $image ) && preg_match('/\.svg$/i', $image[0] ) && $image[1] <= 1 ) {
+ $image[1] = $image[2] = null;
+
+ if ( is_array( $size ) ) {
+ $image[1] = $size[0];
+ $image[2] = $size[1];
+ } elseif ( false !== ( $xml = simplexml_load_file( $image[0] ) ) ) {
+ $attr = $xml->attributes();
+ $viewbox = explode( ' ', $attr->viewBox );
+
+ // Get width
+ if ( isset( $attr->width ) && preg_match( '/\d+/', $attr->width, $value ) ) {
+ $image[1] = (int) $value[0];
+ } elseif ( 4 === count( $viewbox ) ) {
+ $image[1] = (int) $viewbox[2];
+ }
+
+ // Get height
+ if ( isset( $attr->height ) && preg_match( '/\d+/', $attr->height, $value ) ) {
+ $image[2] = (int) $value[0];
+ } elseif ( 4 === count( $viewbox ) ) {
+ $image[2] = (int) $viewbox[3];
+ }
+ }
+ }
+
+ return $image;
+ }
+
/**
* Setup hooks for the filters.
*/
@@ -709,5 +748,7 @@ function ( $type ) use ( $filter ) {
// Filter for block rendering.
add_filter( 'render_block_data', array( $this, 'filter_image_block_pre_render' ), 10, 2 );
+ // Try to get SVGs size.
+ add_filter( 'wp_get_attachment_image_src', array( $this, 'filter_svg_image_size' ), 10, 3 );
}
}
diff --git a/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/media/class-video.php b/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/media/class-video.php
index a461f841f..f971948dd 100644
--- a/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/media/class-video.php
+++ b/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/php/media/class-video.php
@@ -104,6 +104,7 @@ public function init_player() {
if ( ! empty( $has_video ) || ! empty( $video_tags ) ) {
// Setup initial scripts.
wp_enqueue_style( 'cld-player' );
+ wp_enqueue_style( 'cld-player-local', $this->media->plugin->dir_url . 'css/video.css', null, self::PLAYER_VER );
wp_enqueue_script( 'cld-player' );
// Init cld script object.
@@ -240,7 +241,7 @@ public function filter_video_shortcode( $html, $attr ) {
$instance = $this->queue_video_config( $attr['id'], $attr[ $video['fileformat'] ], $video['fileformat'], $args );
// Replace with video tag.
- return '';
+ return '';
}
/**
@@ -369,29 +370,31 @@ public function print_video_scripts() {
var cldVideos = ;
for ( var videoInstance in cldVideos ) {
- var cldConfig = cldVideos[ videoInstance ];
- var cldId = 'cloudinary-video-' + videoInstance;
- cld.videoPlayer( cldId, cldConfig );
+ var cldConfig = cldVideos[ videoInstance ];
+ var cldId = 'cloudinary-video-' + videoInstance;
+ cld.videoPlayer( cldId, cldConfig );
}
window.addEventListener( 'load', function() {
- for ( var videoInstance in cldVideos ) {
- var cldId = 'cloudinary-video-' + videoInstance;
- var videoContainer = document.getElementById( cldId );
- var videoElement = videoContainer.getElementsByTagName( 'video' );
-
- if ( videoElement.length === 1 ) {
- videoElement = videoElement[0];
-
-
- config['video_freeform'] ): ?>
- videoElement.src = videoElement.src.replace(
- 'upload/',
- 'upload/config['video_freeform'] ) ?>/'
- );
-
- }
- }
+ for ( var videoInstance in cldVideos ) {
+ var cldId = 'cloudinary-video-' + videoInstance;
+ var videoContainer = document.getElementById( cldId );
+ var videoElement = videoContainer.getElementsByTagName( 'video' );
+
+ if ( videoElement.length === 1 ) {
+ videoElement = videoElement[0];
+ videoElement.style.width = '100%';
+
+ config['video_freeform'] ): ?>
+ if ( videoElement.src.indexOf( 'config['video_freeform'] ) ?>' ) === -1 ) {
+ videoElement.src = videoElement.src.replace(
+ 'upload/',
+ 'upload/config['video_freeform'] ) ?>/'
+ );
+ }
+
+ }
+ }
} );
media->filter->get_media_tags( $content );
+ foreach ( $video_tags as $tag ) {
+ if ( false !== strpos( $tag, 'class="' ) ) {
+ $content = str_replace( 'class="', 'class="' . $classes . ' ', $content );
+ } else {
+ $content = str_replace( '