Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Contributors: bfintal, gambitph
Tags: image, optimization, compress, convert, webp
Requires at least: 6.7.5
Tested up to: 6.9.4
Tested up to: 7.0
Requires PHP: 8.0
Stable tag: 1.3.1
License: GPLv2 or later
Expand Down
8 changes: 8 additions & 0 deletions src/admin/class-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ public function register_settings() {
],

// Image Optimization settings
'smart_optimization' => [
'type' => 'integer',
],
'webp_quality' => [
'type' => 'integer',
],
Expand Down Expand Up @@ -322,6 +325,11 @@ public function sanitize_options( $options ) {
$sanitized['thumbnail_sizes'] = array_map( 'sanitize_text_field', $options['thumbnail_sizes'] );
}

// Sanitize smart optimization
if ( isset( $options['smart_optimization'] ) ) {
$sanitized['smart_optimization'] = $options['smart_optimization'] ? 1 : 0;
}

// Sanitize webp quality
if ( isset( $options['webp_quality'] ) ) {
$quality = absint( $options['webp_quality'] );
Expand Down
19 changes: 14 additions & 5 deletions src/admin/class-meta-box.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,20 @@ function cimo_get_media_type_label( $mimetype ) {

// Converted format
echo '<li class="cimo-converted">';
echo '🏞️ ' . sprintf(
/* translators: %s: converted format */
esc_html__( 'Converted to %s', 'cimo-image-optimizer' ),
'<span class="cimo-value">' . esc_html( $converted_format ) . '</span>'
);
$converted_format_markup = '<span class="cimo-value">' . esc_html( $converted_format ) . '</span>';
if ( ! empty( $cimo['smartOptimized'] ) ) {
echo '🏞️ ' . sprintf(
/* translators: %s: converted format */
esc_html__( 'Smart optimized to %s', 'cimo-image-optimizer' ),
$converted_format_markup
);
} else {
echo '🏞️ ' . sprintf(
/* translators: %s: converted format */
esc_html__( 'Converted to %s', 'cimo-image-optimizer' ),
$converted_format_markup
);
}
echo '</li>';

// Conversion time
Expand Down
7 changes: 7 additions & 0 deletions src/admin/class-metadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public function register_rest_route() {
'convertedFilesize',
'conversionTime',
'compressionSavings',
'smartOptimized',
];
if ( ! is_array( $value ) ) {
// translators: The %s is the parameter name.
Expand Down Expand Up @@ -85,6 +86,7 @@ public function register_rest_route() {
'convertedFilesize',
'conversionTime',
'compressionSavings',
'smartOptimized',
];
$sanitized = [];
if ( is_array( $value ) ) {
Expand All @@ -98,6 +100,8 @@ public function register_rest_route() {
$entry[ $key ] = intval( $item[ $key ] );
} elseif ( in_array( $key, [ 'conversionTime', 'compressionSavings' ], true ) ) {
$entry[ $key ] = floatval( $item[ $key ] );
} elseif ( $key === 'smartOptimized' ) {
$entry[ $key ] = ! empty( $item[ $key ] ) ? 1 : 0;
} else {
$entry[ $key ] = sanitize_text_field( $item[ $key ] );
}
Expand Down Expand Up @@ -137,6 +141,7 @@ public function save_metadata( $request ) {
'convertedFilesize',
'conversionTime',
'compressionSavings',
'smartOptimized',
];
$sanitized_metadata = [];
foreach ( $metadata_array as $item ) {
Expand All @@ -149,6 +154,8 @@ public function save_metadata( $request ) {
$entry[ $key ] = intval( $item[ $key ] );
} elseif ( in_array( $key, [ 'conversionTime', 'compressionSavings' ], true ) ) {
$entry[ $key ] = floatval( $item[ $key ] );
} elseif ( $key === 'smartOptimized' ) {
$entry[ $key ] = ! empty( $item[ $key ] ) ? 1 : 0;
} else {
$entry[ $key ] = sanitize_text_field( $item[ $key ] );
}
Expand Down
3 changes: 3 additions & 0 deletions src/admin/class-script-loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ public static function enqueue_cimo_assets() {
'canManageOptions' => current_user_can( 'manage_options' ),
'optimizeAllMedia' => isset( $settings['optimize_all_media'] ) ? (int) $settings['optimize_all_media'] : 0,
'isPremium' => CIMO_BUILD === 'premium',
'smartOptimization' => CIMO_BUILD === 'premium'
? ( isset( $settings['smart_optimization'] ) ? (int) $settings['smart_optimization'] : 1 )
: 0,
'webpQuality' => ! empty( $settings['webp_quality'] ) ? (int) $settings['webp_quality'] : 80,
'maxImageDimension' => ! empty( $settings['max_image_dimension'] ) ? (int) $settings['max_image_dimension'] : 0,
'videoOptimizationEnabled' => isset( $settings['video_optimization_enabled'] ) ? (int) $settings['video_optimization_enabled'] : 1,
Expand Down
20 changes: 20 additions & 0 deletions src/admin/css/admin-page.css
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,26 @@
order: 1;
}

.cimo-smart-optimization-toggle {
order: 2;

~ .cimo-setting-field {
order: 3;
}

~ .cimo-webp-quality-range-control {
order: 1;
}

~ .cimo-reset-button {
order: 10;
}
}

.cimo-is-premium .cimo-smart-optimization-toggle {
order: 1;
}

@keyframes cimo-bulk-optimizer-blink {

0%, 100% { opacity: 1; }
Expand Down
12 changes: 3 additions & 9 deletions src/admin/js/media-manager/drop-zone.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,22 +103,18 @@ function addDropZoneListenerToMediaManager( targetDocument ) {
const progressModal = new ProgressModal( fileConverters, onCancel )
progressModal.open()

let hasError = false

// Process and optimize each media file here,
// e.g. converting to webp, resizing, compressing, etc.
const optimizedResults = await Promise.all(
fileConverters.map( async converter => {
try {
const result = await converter.convert()
const result = await converter.optimize()
if ( result.error ) {
// eslint-disable-next-line no-console
console.warn( result.error )
hasError = true
}
return result
} catch ( error ) {
hasError = true
// eslint-disable-next-line no-console
console.warn( error )
return { file: converter.file, metadata: null }
Expand Down Expand Up @@ -216,10 +212,8 @@ function addDropZoneListenerToMediaManager( targetDocument ) {
}
}

// If there's an error, do not close the progress modal so the user can read the error.
if ( ! hasError ) {
progressModal.close()
}
// Close when optimization finishes, including when we fall back to the original file after an error.
progressModal.close()
}

// Add our custom drop listener
Expand Down
111 changes: 98 additions & 13 deletions src/admin/js/media-manager/progress-modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,34 @@ class ProgressModal {
this.interval = null
this.modal = null
this.progressBars = []
this._setupModal()
this.delayTimeout = null
}

open() {
if ( ! this.modal ) {
return
}
if ( this.converters.length === 0 ) {
return
}
this.modal.style.display = 'flex'
this._startInterval()

const delays = this.converters
.map( c => c?.progressDelay )
.filter( v => typeof v === 'number' && v > 0 )

// Only delay if all converter opt to delay, to allow
// big media files like video to show the progress modal immediately.
const shouldDelay = delays.length === this.converters.length
const delay = shouldDelay ? Math.max( ...delays ) : 0

const start = () => {
this._setupModal()
this.modal.style.display = 'flex'
this._startInterval()
}

if ( delay > 0 ) {
this.delayTimeout = setTimeout( start, delay )
} else {
start()
}
}

_handleCloseClick() {
Expand All @@ -37,6 +53,10 @@ class ProgressModal {
}

close() {
if ( this.delayTimeout ) {
clearTimeout( this.delayTimeout )
this.delayTimeout = null
}
if ( ! this.modal ) {
return
}
Expand Down Expand Up @@ -150,9 +170,43 @@ class ProgressModal {
this.modal.appendChild( wrapper )
document.body.appendChild( this.modal )

this._ensureIndeterminateStyles()
this._renderProgressBars()
}

_ensureIndeterminateStyles() {
if ( document.getElementById( 'cimo-progress-indeterminate-styles' ) ) {
return
}
const style = document.createElement( 'style' )
style.id = 'cimo-progress-indeterminate-styles'
style.textContent = `
.cimo-progress-indeterminate-layer {
display: none;
position: absolute;
inset: 0;
overflow: hidden;
border-radius: inherit;
pointer-events: none;
}
.cimo-progress-indeterminate-bar {
position: absolute;
top: 0;
left: -35%;
width: 35%;
height: 100%;
border-radius: 5px;
background: linear-gradient(90deg, #00d8f0 0%, #2bc566 100%);
animation: cimo-indet-sweep 1.35s ease-in-out infinite;
}
@keyframes cimo-indet-sweep {
from { left: -35%; }
to { left: 100%; }
}
`
document.head.appendChild( style )
}

_renderProgressBars() {
this.progressList.innerHTML = ''
this.progressBars = []
Expand Down Expand Up @@ -259,22 +313,31 @@ class ProgressModal {
height: 8px;
width: 100%;
overflow: hidden;
position: relative;
`
const indeterminateLayer = document.createElement( 'div' )
indeterminateLayer.className = 'cimo-progress-indeterminate-layer'
const indeterminateBar = document.createElement( 'div' )
indeterminateBar.className = 'cimo-progress-indeterminate-bar'
indeterminateLayer.appendChild( indeterminateBar )

const bar = document.createElement( 'div' )
bar.className = 'cimo-progress-bar'
bar.style.cssText = `
background: linear-gradient(90deg, #00d8f0 0%, #2bc566 100%);
width: 0%;
height: 100%;
transition: width 0.5s linear;
transition: width 0.65s cubic-bezier(0.4, 0, 0.2, 1);
border-radius: 5px 0 0 5px;
`

bar.sizeLabelEl = sizeLabel
bar.statusLabelEl = statusLabel
bar.percentageLabelEl = percentageLabel
bar.indeterminateLayer = indeterminateLayer

barBg.appendChild( bar )
barBg.appendChild( indeterminateLayer )
barContainer.appendChild( label )
barContainer.appendChild( sizeLabel )
barContainer.appendChild( progressStatusFlex )
Expand All @@ -300,10 +363,19 @@ class ProgressModal {
}

_updateProgress() {
if ( ! this.modal ) {
return
}

let allDone = true
let hasError = false

this.converters.forEach( ( converter, i ) => {
const barEl = this.progressBars[ i ]
const isIndeterminate = converter.indeterminateProgress === true &&
converter.progress < 1 &&
! converter.errorMessage

let percent = converter.progress * 100

if (
Expand All @@ -325,18 +397,31 @@ class ProgressModal {
this.errorNote.style.display = 'block'
}

if ( this.progressBars[ i ] ) {
this.progressBars[ i ].statusLabelEl.style.cssText = `
if ( barEl ) {
barEl.statusLabelEl.style.cssText = `
color: ${ converter.errorMessage ? '#dc3545' : 'inherit' };
`
this.progressBars[ i ].statusLabelEl.innerText = converter.errorMessage || converter.status
this.progressBars[ i ].style.width = percent + '%'
this.progressBars[ i ].percentageLabelEl.innerText = parseInt( percent ) + '%'
barEl.statusLabelEl.innerText = converter.errorMessage || converter.status

if ( isIndeterminate ) {
barEl.style.display = 'none'
if ( barEl.indeterminateLayer ) {
barEl.indeterminateLayer.style.display = 'block'
}
barEl.percentageLabelEl.innerText = __( '…', 'cimo-image-optimizer' )
} else {
barEl.style.display = ''
if ( barEl.indeterminateLayer ) {
barEl.indeterminateLayer.style.display = 'none'
}
barEl.style.width = percent + '%'
barEl.percentageLabelEl.innerText = parseInt( percent ) + '%'
}
}
} )

// Optional: auto-close when all converters are done (progress 100%)
if ( allDone && this.modal.style.display === 'block' ) {
if ( allDone && this.modal && this.modal.style.display !== 'none' ) {
if ( ! hasError ) {
setTimeout( () => this.close(), 750 )
}
Expand Down
12 changes: 3 additions & 9 deletions src/admin/js/media-manager/select-files.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,22 +82,18 @@ function addSelectFilesListenerToFileUploads( targetDocument ) {
const progressModal = new ProgressModal( fileConverters, onCancel )
progressModal.open()

let hasError = false

// Process and optimize each media file here,
// e.g. converting to webp, resizing, compressing, etc.
const optimizedResults = await Promise.all(
fileConverters.map( async converter => {
try {
const result = await converter.convert()
const result = await converter.optimize()
if ( result.error ) {
// eslint-disable-next-line no-console
console.warn( result.error )
hasError = true
}
return result
} catch ( error ) {
hasError = true
// eslint-disable-next-line no-console
console.warn( error )
return { file: converter.file, metadata: null }
Expand Down Expand Up @@ -127,10 +123,8 @@ function addSelectFilesListenerToFileUploads( targetDocument ) {
changeEvent.__cimo_converted = true // eslint-disable-line camelcase
event.target.dispatchEvent( changeEvent )

// If there's an error, do not close the progress modal so the user can read the error.
if ( ! hasError ) {
progressModal.close()
}
// Close when optimization finishes, including when we fall back to the original file after an error.
progressModal.close()
}

if ( ! targetDocument.body.__cimo_selectfiles_listener_attached ) {
Expand Down
Loading
Loading