Skip to content

Commit 208605a

Browse files
authored
release(major): new features
### New Features - Added [client-side detection](https://docs.optimole.com/article/1948-bypass-lazy-load-for-first-images) of above-the-fold images with device-specific lazy loading for improved performance on both desktop and mobile. - Introduced [video](https://docs.optimole.com/article/2254-how-to-use-optimole-video-integration) integration that allows uploading, managing, and displaying videos directly via the Optimole DAM. - Enabled rename and replace functionality for media files within both the WordPress media library and the Optimole Cloud Library. - Simplified compression settings with [presets](https://docs.optimole.com/article/2252-choose-the-best-optimization-preset-for-your-website) for Speed and Quality optimized workflows. - Added a download button in the Optimole Cloud Library for quick image retrieval. - Introduced a WordPress dashboard widget showing visits, optimizations, and latest media activity. - Launched a [referral](https://docs.optimole.com/article/2253-referral-program) program where each referral grants 500 extra visits, up to 5,000. - Added support to host and serve PDFs from the Optimole. - Added support for JPEG XL format --- ### Enhancements - Added direct access to the Optimole Cloud Library from the plugin settings for faster navigation. - Redesigned the plugin dashboard layout to make metrics clearer and easier to read. - Enhanced Optimole badge settings with position options and icon-only display mode. - Added sorting options in the Cloud Library to organize media by upload time or file size. - Refreshed the first plugin screen with improved trust-building elements. - Enhanced image preloading logic to more accurately detect and prioritize visible images. - Displayed clear warnings when free users are approaching their offload limits. - Added slider navigation and persistent folder state to the Cloud Library for a better media browsing experience. - Displayed offload quota usage directly in the plugin dashboard. --- ### Bug Fixes - Fixed pixelated SVGs by ensuring proper format is served. - Prevented redirect issues when rolling back offloaded images in the media library. - Respected custom image dimensions set in Elementor sliders during auto-scaling. - Stopped misidentification of mega menu images as hero images. - Prevented broken links when editing cloud-only images by redirecting to the Optimole Library. - Preserved original image URLs in Gutenberg when lazy load and scaling are disabled. - Fixed issue where product gallery images from the Cloud Library also appeared in product descriptions. - Resolved incorrect quota display for disabled accounts with badge enabled. - Ensured first-time DAM authorization works across all browsers. - Corrected sorting so newest uploads appear at the top of the Cloud Library. - Cleared cache automatically when images are updated on the site. - Made update and delete buttons for watermarks visible when multiple rows exist. - Clarified that excluding an image from optimization also excludes it from lazy loading. - Stopped image distortion when no size attributes are present and scaling is disabled. - Synced folder tree view and search in the Cloud Library for consistent navigation.
2 parents 0df1550 + a3222d1 commit 208605a

File tree

107 files changed

+9160
-1642
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+9160
-1642
lines changed

.github/workflows/build-dev-artifacts.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
run: |
3030
echo "::set-output name=dir::$(composer config cache-files-dir)"
3131
- name: Configure Composer cache
32-
uses: actions/cache@v1
32+
uses: actions/cache@v4
3333
with:
3434
path: ${{ steps.composer-cache.outputs.dir }}
3535
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ build
1010
.DS_Store
1111
cc-test-reporter
1212
assets/build
13-
test-results
13+
test-results
14+
tests/assets/filestash

assets/css/single-attachment.css

+241
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
table.compat-attachment-fields {
2+
border-collapse: collapse;
3+
width: 100%;
4+
}
5+
6+
[class^="compat-field-optml_"] {
7+
background: #fff;
8+
border-collapse: separate;
9+
border-spacing: 0;
10+
border: 1px solid #ccc;
11+
}
12+
13+
[class^="compat-field-optml_"] tr {
14+
background: #fff;
15+
}
16+
17+
[class^="compat-field-optml_"] th {
18+
display: block;
19+
float: none;
20+
white-space: nowrap;
21+
}
22+
23+
[class^="compat-field-optml_"] th,
24+
[class^="compat-field-optml_"] td {
25+
padding: 20px;
26+
}
27+
28+
.compat-field-optml_footer_row {
29+
padding: 0 !important;
30+
background: #eee;
31+
}
32+
33+
.compat-field-optml_spacer_row {
34+
height: 40px !important;
35+
background: transparent !important;
36+
border: 0 !important;
37+
}
38+
39+
.compat-field-optml_spacer_row td,
40+
.compat-field-optml_spacer_row th {
41+
padding: 0 !important;
42+
}
43+
44+
.compat-field-optml_footer_row th,
45+
.compat-field-optml_footer_row td {
46+
padding: 5px 20px;
47+
}
48+
49+
50+
.optml-logo-contianer {
51+
justify-content: flex-end;
52+
display: flex;
53+
align-items: center;
54+
gap: 10px;
55+
font-size: 12px;
56+
position:relative;
57+
}
58+
59+
.optml-logo-contianer img {
60+
width: 25px;
61+
height: 25px;
62+
}
63+
64+
.optml-rename-input:focus-within {
65+
box-shadow: 0 0 0 1px #577BF9;
66+
}
67+
68+
.optml-rename-media-container {
69+
display: flex;
70+
gap: 10px;
71+
align-items: center;
72+
}
73+
74+
.optml-rename-input {
75+
display: flex;
76+
align-items: stretch;
77+
border-radius: 3px;
78+
border: 1px solid #577BF9;
79+
overflow: hidden;
80+
background: #fff;
81+
flex-grow: 1;
82+
}
83+
84+
.optml-rename-input #optml_rename_file {
85+
border: 0;
86+
border-radius: 0;
87+
flex-grow: 1;
88+
box-shadow: none;
89+
background: transparent;
90+
min-height: 30px;
91+
}
92+
93+
.optml-rename-input .optml-file-ext {
94+
padding: 0 10px;
95+
display: flex;
96+
align-items: center;
97+
font-weight: 600;
98+
background-color: #e6effd;
99+
border-left: 1px solid #577BF9;
100+
color: #577BF9;
101+
}
102+
103+
104+
.optml-replace-section {
105+
display: flex;
106+
flex-direction: column;
107+
gap: 10px;
108+
}
109+
110+
.optml-description {
111+
color: #666;
112+
margin: 0;
113+
font-style: italic;
114+
}
115+
116+
.optml-replace-input {
117+
box-sizing: border-box;
118+
display: flex;
119+
flex-direction: column;
120+
align-items: flex-end;
121+
gap: 10px;
122+
}
123+
124+
.optml-replace-input label {
125+
width: 100%;
126+
min-height: 100px;
127+
display: flex;
128+
align-items: center;
129+
justify-content: center;
130+
text-align: center;
131+
cursor: pointer;
132+
flex-grow: 1;
133+
padding: 8px;
134+
border: 1px dashed #577BF9;
135+
border-radius: 3px;
136+
background: #fff;
137+
transition: all 0.3s ease;
138+
}
139+
140+
.optml-replace-input label:hover {
141+
background: #577BF9;
142+
color: #fff;
143+
}
144+
145+
.optml-replace-file-preview {
146+
display: flex;
147+
align-items: center;
148+
gap: 10px;
149+
justify-content: center;
150+
font-weight: 600;
151+
}
152+
153+
.optml-replace-file-preview img {
154+
object-fit: cover;
155+
border-radius: 6px;
156+
max-width: 250px;
157+
max-height: 75px;
158+
border: 1px solid #ccc;
159+
background: #f0f0f0;
160+
}
161+
162+
.optml-replace-file-error {
163+
color: rgb(163, 11, 0);
164+
padding: 5px 10px;
165+
border-radius: 3px;
166+
border: 1px solid rgb(163, 11, 0);
167+
background:rgb(255, 205, 201);
168+
}
169+
170+
#optml-file-drop-area {
171+
box-sizing: border-box;
172+
position: relative;
173+
transition: all 0.3s ease;
174+
}
175+
176+
#optml-file-drop-area.drag-active {
177+
background-color: #e6effd;
178+
border: 1px dashed #577BF9;
179+
}
180+
181+
.optml-replace-file-actions {
182+
display: flex;
183+
align-items: center;
184+
flex-direction: row-reverse;
185+
justify-content: flex-end;
186+
gap: 10px;
187+
width: 100%;
188+
}
189+
190+
.optml-rename-actions {
191+
display: flex;
192+
align-items: center;
193+
justify-content: flex-end;
194+
width: 100%;
195+
margin-top: 10px;
196+
}
197+
198+
.optml-replace-file-actions p {
199+
margin-right: auto;
200+
}
201+
202+
[class^="compat-field-optml_"] .optml-btn {
203+
border-radius: 3px !important;
204+
border: 0 !important;
205+
cursor: pointer;
206+
transition: all 0.3s ease;
207+
color: #fff !important;
208+
margin-bottom: 0 !important;
209+
}
210+
211+
[class^="compat-field-optml_"] .optml-btn.primary {
212+
background: #577BF9 !important;
213+
}
214+
215+
[class^="compat-field-optml_"] .optml-btn.destructive {
216+
background: #D93025 !important;
217+
}
218+
219+
[class^="compat-field-optml_"] .optml-btn:disabled {
220+
opacity: 0.5;
221+
cursor: not-allowed !important;
222+
pointer-events: none;
223+
color: #fff !important;
224+
}
225+
226+
.optml-btn.primary:hover {
227+
background: #4161d7;
228+
}
229+
230+
.optml-btn.destructive:hover {
231+
background: #c2291e;
232+
}
233+
234+
.optml-svg-loader {
235+
animation: spin 1s linear infinite;
236+
}
237+
238+
@keyframes spin {
239+
0% { transform: rotate(0deg); }
240+
100% { transform: rotate(360deg); }
241+
}

assets/js/media.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
jQuery(document).ready(function($) {
2+
jQuery('.move-image-optml').click(function() {
3+
//get the id and send a jquery rest request to the server
4+
var id = jQuery(this).data('id');
5+
var action = jQuery(this).data('action');
6+
moveImage(id, action, jQuery(this));
7+
});
8+
});
9+
10+
function moveImage(id, action, element, is_retry = false) {
11+
//add a loading indicator
12+
element.parent().find('.spinner').addClass('is-active');
13+
element.parent().addClass('is-loading');
14+
jQuery.ajax({
15+
url: optimoleMediaListing.rest_url,
16+
type: 'POST',
17+
headers: {
18+
'X-WP-Nonce': optimoleMediaListing.nonce
19+
},
20+
data: {
21+
action: action,
22+
status: is_retry ? 'check' : 'start',
23+
id: id
24+
},
25+
success: function(response) {
26+
if(response.code === 'moved') {
27+
element.parent().find('.spinner').removeClass('is-active');
28+
element.parent().removeClass('is-loading');
29+
element.parent().find('.move-image-optml').toggleClass('hidden');
30+
31+
}else if(response.code === 'error'){
32+
element.parent().find('.spinner').removeClass('is-active');
33+
element.parent().removeClass('is-loading');
34+
element.parent().text(response.data);
35+
}else{
36+
setTimeout(function() {
37+
moveImage(id, action, element, true);
38+
}, 1000);
39+
}
40+
}
41+
});
42+
}

0 commit comments

Comments
 (0)