Skip to content

Commit 1d35f15

Browse files
committed
Merge branch 'develop'
2 parents 11c70e0 + 066801e commit 1d35f15

File tree

5 files changed

+115
-54
lines changed

5 files changed

+115
-54
lines changed

readme.txt

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Requires at least: 4.8
55
Donate Link: https://givewp.com/
66
Tested up to: 6.5
77
Requires PHP: 7.4
8-
Stable tag: 2.0.4
8+
Stable tag: 2.0.5
99
License: GPLv3
1010
License URI: http://www.gnu.org/licenses/gpl-3.0.html
1111

@@ -106,6 +106,11 @@ This is the first version of this plugin. It is a tool for your convenience. Rol
106106

107107
== Changelog ==
108108

109+
= 2.0.5 =
110+
* New: In this version we've brought back the "trunk" option to rollback to. This allows plugin or theme developers who use trunk for beta testing to rollback to the latest trunk version. Thanks, @megamenu for suggesting this be brought back.
111+
* Fix: Refactored how plugin avatar images are checked so that all available image types and sizes are checked. This resolves an issue where some plugins would not display an avatar image.
112+
* Fix: On the final rollback confirmation screen, the plugin name field was outputting raw HTML. This has been fixed to properly display the plugin name, even if it contains some html characters.
113+
109114
= 2.0.4 =
110115
* Fix: Resolved issue REST route not including proper permission callback which created a PHP notice. Thanks, @rom1our for submitting the issue.
111116
* Fix: Resolve issue with REST API and multisite installs not being able to properly communicate with the endpoint.

src/TrunkPopover.js

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { useState } from '@wordpress/element';
2+
import { Dashicon, Popover } from '@wordpress/components';
3+
import { __ } from '@wordpress/i18n';
4+
5+
function TrunkPopover() {
6+
const [ isPopoverVisible, setIsPopoverVisible ] = useState( false );
7+
8+
const showPopover = () => {
9+
setIsPopoverVisible(true);
10+
};
11+
12+
const hidePopover = () => {
13+
setIsPopoverVisible(false);
14+
};
15+
16+
return (
17+
<div className={'wpr-popover-wrap'}>
18+
<Dashicon icon={'info'} onMouseEnter={showPopover} onMouseLeave={hidePopover} />
19+
{isPopoverVisible && (
20+
<Popover position={'top'} className={'wpr-popover'} variant={'unstyled'} onClose={hidePopover} noArrow={false}>
21+
{__( 'Trunk is where the most current revisions of the code should be stored, often representing the development version of the software. This is particularly relevant for developers and testers who are working with the very latest code changes that have not yet been released to the public.', 'wp-rollback' )}
22+
</Popover>
23+
)}
24+
</div>
25+
);
26+
}
27+
28+
export default TrunkPopover;

src/admin.js

+52-46
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import './admin.scss';
2-
import { Button, Dashicon, Modal, Spinner } from '@wordpress/components';
2+
import { Button, Dashicon, Modal, Popover, Spinner } from '@wordpress/components';
33
import { render, useEffect, useState } from '@wordpress/element';
44
import { __, _n, sprintf } from '@wordpress/i18n';
55
import domReady from '@wordpress/dom-ready';
66
import { decodeEntities } from '@wordpress/html-entities';
77
import { getQueryArgs } from '@wordpress/url';
88
import ExpandableText from './ExpandableText';
9+
import TrunkPopover from './TrunkPopover';
910

1011
const AdminPage = () => {
1112

@@ -27,9 +28,9 @@ const AdminPage = () => {
2728

2829
let restUrl = `${wprData.restUrl}wp-rollback/v1/fetch-info/?type=${queryArgs.type}&slug=${queryArgs.type === 'theme' ? queryArgs.theme_file : queryArgs.plugin_slug}`;
2930

30-
const headers = new Headers({
31-
'X-WP-Nonce': wprData.restApiNonce // Assuming nonce is stored in wprData.nonce
32-
});
31+
const headers = new Headers( {
32+
'X-WP-Nonce': wprData.restApiNonce, // Assuming nonce is stored in wprData.nonce
33+
} );
3334

3435
fetch( restUrl, { headers: headers } )
3536
.then( ( response ) => response.json() )
@@ -40,38 +41,38 @@ const AdminPage = () => {
4041
.catch( ( error ) => {
4142
console.error( 'Error fetching data:', error );
4243
} );
43-
}, [wprData] );
44-
45-
useEffect( () => {
46-
if ( rollbackInfo && rollbackInfo.slug ) { // Check if rollbackInfo is loaded and has a slug
47-
checkImage( `https://ps.w.org/${rollbackInfo.slug}/assets/icon-128x128.png`, ( exists ) => {
48-
if ( exists ) {
49-
setImageUrl( `https://ps.w.org/${rollbackInfo.slug}/assets/icon-128x128.png` );
50-
} else {
51-
checkImage( `https://ps.w.org/${rollbackInfo.slug}/assets/icon-128x128.jpg`, ( exists ) => {
52-
if ( exists ) {
53-
setImageUrl( `https://ps.w.org/${rollbackInfo.slug}/assets/icon-128x128.jpg` );
54-
} else {
55-
checkImage( `https://ps.w.org/${rollbackInfo.slug}/assets/icon-128x128.gif`, ( exists ) => {
56-
if ( exists ) {
57-
setImageUrl( `https://ps.w.org/${rollbackInfo.slug}/assets/icon-128x128.gif` );
58-
} else {
59-
setImageUrl( wprData.avatarFallback );
60-
}
61-
} );
44+
}, [ wprData ] );
45+
46+
useEffect(() => {
47+
const checkAndSetImage = async () => {
48+
if (rollbackInfo && rollbackInfo.slug) {
49+
const sizes = ['icon-256x256', 'icon-128x128', 'icon'];
50+
const extensions = ['png', 'jpg', 'gif', 'svg'];
51+
52+
for (let size of sizes) {
53+
for (let ext of extensions) {
54+
const url = `https://ps.w.org/${rollbackInfo.slug}/assets/${size}.${ext}`;
55+
const exists = await checkImage(url);
56+
if (exists) {
57+
setImageUrl(url);
58+
return;
6259
}
63-
} );
60+
}
6461
}
65-
} );
66-
}
67-
}, [ rollbackInfo ] );
68-
69-
// @TODO: Refactor to remove this function because the API should return false if the image doesn't exist.
70-
function checkImage( url, callback ) {
71-
var img = new Image();
72-
img.onload = () => callback( true );
73-
img.onerror = () => callback( false );
74-
img.src = url;
62+
setImageUrl(wprData.avatarFallback);
63+
}
64+
};
65+
66+
checkAndSetImage();
67+
}, [rollbackInfo]);
68+
69+
function checkImage(url) {
70+
return new Promise((resolve, reject) => {
71+
var img = new Image();
72+
img.onload = () => resolve(true);
73+
img.onerror = () => resolve(false);
74+
img.src = url;
75+
});
7576
}
7677

7778
if ( isLoading ) {
@@ -184,7 +185,7 @@ const AdminPage = () => {
184185
{queryArgs.type === 'plugin' && (
185186
<a href={`https://wordpress.org/plugins/${rollbackInfo.slug}/`} target={'_blank'}
186187
className={'wpr-heading-link'}
187-
// translators: %s Plugin or Theme name.
188+
// translators: %s Plugin or Theme name.
188189
alt={sprintf( __( 'View %s on WordPress.org', 'wp-rollback' ), rollbackInfo.name )}
189190
>
190191
{decodeEntities( rollbackInfo.name )}
@@ -194,7 +195,7 @@ const AdminPage = () => {
194195
{queryArgs.type === 'theme' && (
195196
<a href={rollbackInfo.homepage} target={'_blank'}
196197
className={'wpr-heading-link'}
197-
// translators: %s Plugin or Theme name.
198+
// translators: %s Plugin or Theme name.
198199
alt={sprintf( __( 'View %s on WordPress.org', 'wp-rollback' ), rollbackInfo.name )}>
199200
{decodeEntities( rollbackInfo.name )}
200201
<Dashicon icon="external"/>
@@ -262,11 +263,14 @@ const AdminPage = () => {
262263

263264
<div className={'wpr-versions-container'}>
264265
{Object.keys( rollbackInfo.versions )
265-
.filter( version => version !== 'trunk' ) // remove 'trunk'
266-
.sort( ( a, b ) => b.localeCompare( a, undefined, {
267-
numeric : true,
268-
sensitivity: 'base',
269-
} ) ) // reverse the order
266+
.sort((a, b) => {
267+
if (a === 'trunk') return 1; // Always places 'trunk' at the end
268+
if (b === 'trunk') return -1; // Always places 'trunk' at the end
269+
return b.localeCompare(a, undefined, {
270+
numeric: true,
271+
sensitivity: 'base',
272+
});
273+
})
270274
.map( ( version, index ) => (
271275
<div key={index}
272276
className={`wpr-version-wrap ${rollbackVersion === version ? 'wpr-active-row' : ''}`}>
@@ -278,11 +282,13 @@ const AdminPage = () => {
278282
onChange={() => setIsRollbackVersion( version )} // Add this line
279283
/>
280284
<span className={'wpr-version-lineitem'}>{version}</span>
281-
{( queryArgs.current_version === version ) && ( version !== 'trunk' ) && (
285+
{( queryArgs.current_version === version ) && (
282286
<span
283287
className={'wpr-version-lineitem-current'}>{__( 'Currently Installed', 'wp-rollback' )}</span>
284288
)}
285-
289+
{( 'trunk' === version ) && (
290+
<TrunkPopover />
291+
)}
286292
</label>
287293
</div>
288294
</div>
@@ -337,7 +343,9 @@ const AdminPage = () => {
337343
htmlFor="tablecell">{queryArgs.type === 'plugin' ? __( 'Plugin Name:', 'wp-rollback' ) : __( 'Theme Name:', 'wp-rollback' )}
338344
</label>
339345
</td>
340-
<td><span className="wpr-plugin-name">{rollbackInfo.name}</span></td>
346+
<td><span className="wpr-plugin-name" dangerouslySetInnerHTML={{
347+
__html:rollbackInfo.name
348+
}}></span></td>
341349
</tr>
342350
<tr className="alternate">
343351
<td className="row-title">
@@ -388,8 +396,6 @@ const AdminPage = () => {
388396
className={'wpr-button-cancel'}>{__( 'Cancel', 'wp-rollback' )}</Button>
389397
</div>
390398
</form>
391-
392-
393399
</Modal>
394400
)}
395401

src/admin.scss

+28-6
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ $container-width: 802px;
5353
height: auto;
5454
margin: 0 0 25px;
5555
}
56-
p{
56+
57+
p {
5758
margin: 0;
5859
padding: 0;
5960
}
@@ -265,32 +266,39 @@ $container-width: 802px;
265266
&.wpr-active-row {
266267
background: #F1F8FF;
267268
}
269+
270+
.wpr-popover-wrap {
271+
display: inline-block;
272+
margin-left: 10px;
273+
}
268274
}
269275

276+
// Radios listing versions
270277
.wpr-version-radio-wrap {
271278
margin: 0;
272279
padding: 0;
273280

274281
label {
275-
display: block;
282+
display: flex;
276283
padding: 20px 30px;
284+
align-items: center;
277285
}
278286

279287
input[type="radio"] {
280-
margin: -5px 0 0;
288+
margin: 0;
281289
}
282290

283291
span.wpr-version-lineitem {
284292
font-size: 18px;
285293
font-weight: 600;
286-
margin: 0 0 6px 8px;
294+
margin: 0 0 0 8px;
287295
}
288296

289297
span.wpr-version-lineitem-current {
290298
font-size: 15px;
291299
font-style: italic;
292300
font-weight: 400;
293-
margin: 0 0 6px 20px;
301+
margin: 0 0 0 20px;
294302
}
295303
}
296304

@@ -346,9 +354,23 @@ $container-width: 802px;
346354

347355
}
348356

357+
// Popover
358+
.wpr-popover {
359+
padding: 12px;
360+
background: #FFF;
361+
border: 1px solid $border-color;
362+
box-shadow: 0 0 10px rgb(0 0 0 / 9%);
363+
max-width: 300px;
364+
font-size: 15px;
365+
line-height: 1.4em;
366+
367+
.components-popover__content {
368+
width: auto;
369+
}
370+
371+
}
349372

350373
// Loading
351-
352374
.wpr-loading-content {
353375
display: flex;
354376
justify-content: center;

wp-rollback.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Description: Rollback (or forward) any WordPress.org plugin, theme or block like a boss.
66
* Author: WP Rollback
77
* Author URI: https://wprollback.com/
8-
* Version: 2.0.4
8+
* Version: 2.0.5
99
* Text Domain: wp-rollback
1010
* Domain Path: /languages
1111
*

0 commit comments

Comments
 (0)