diff --git a/.distignore b/.distignore index 028aa9d..b7be7f3 100644 --- a/.distignore +++ b/.distignore @@ -1,14 +1,13 @@ .git .github -.wordpress-org -node_modules +.wordpress-orgnode_modules src/*.js -src/**/*.js .editorconfig .gitignore .prettierignore .prettierrc.json +.prettierrc.js composer.json composer.lock package.json diff --git a/.editorconfig b/.editorconfig index 76fdcd3..5535dec 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,6 +9,7 @@ tab_width = 4 indent_style = space insert_final_newline = true trim_trailing_whitespace = true +max_line_length = 120 [*.txt] trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore index 2696cac..91dd377 100644 --- a/.gitignore +++ b/.gitignore @@ -4,14 +4,10 @@ logs npm-debug.log* yarn-debug.log* yarn-error.log* - -# Coverage directory used by tools like istanbul -coverage +.idea # Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release /build -/src/Strauss # Dependency directories node_modules/ @@ -25,11 +21,20 @@ node_modules/ # Output of 'npm pack' *.tgz -# dotenv environment variables file +# dotenv environment variables files and directories .env +.prettierignore +.prettierrc +.gitignore +/.idea/ +.vscode +.DS_Store # No composer stuff /vendor/ # No language files /languages/* + +# Catch alls +wp-rollback.zip diff --git a/.prettierignore b/.prettierignore index 4bd56d2..1d50f46 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,12 +1,12 @@ -# Ignore node modules -node_modules/* +# Ignore directories +.github +assets +build +node_modules +languages -# Ignore Composer packages -vendor/* - -# Ignore Directories -sample-data/* - -# Ignore Files -package-lock.json +# Ignore files composer.lock +package-lock.json +phpcs.xml +.php-cs-fixer.cache diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..7669fbc --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,10 @@ +const defaultConfig = require( '@wordpress/scripts/config/.prettierrc.js' ); + +// Add customizations to WordPress prettier config. +const config = { + ...defaultConfig, + printWidth: 120, + useTabs: false, +}; + +module.exports = config; diff --git a/.prettierrc.json b/.prettierrc.json deleted file mode 100644 index fa858b5..0000000 --- a/.prettierrc.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "tabWidth": 4, - "trailingComma": "es5", - "printWidth": 120, - "bracketSpacing": false, - "singleQuote": true -} diff --git a/package.json b/package.json index 06827f7..964d6c4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "wp-rollback", - "version": "2.0.0", + "version": "2.0.7", "description": "Rollback (or forward) any WordPress.org plugin, theme, or block like a boss.", "homepage": "https://wprollback.com", "author": "WP Rollback", diff --git a/readme.txt b/readme.txt index 6a9f87c..9e18d8a 100644 --- a/readme.txt +++ b/readme.txt @@ -1,11 +1,11 @@ === WP Rollback - Rollback Plugins and Themes === Contributors: dlocc, drrobotnik, webdevmattcrom, givewp Tags: rollback, revert, downgrade, version, plugins, themes, version, versions, backup, backups, revision, revisions -Requires at least: 5.0 +Requires at least: 6.0 Donate Link: https://givewp.com/ -Tested up to: 6.5 +Tested up to: 6.6 Requires PHP: 7.4 -Stable tag: 2.0.6 +Stable tag: 2.0.7 License: GPLv3 License URI: http://www.gnu.org/licenses/gpl-3.0.html @@ -106,6 +106,11 @@ This is the first version of this plugin. It is a tool for your convenience. Rol == Changelog == += 2.0.7 = +* Fix: Resolved a bug with plain permalink websites which caused a `rest_no_route` error when trying to rollback a plugin or theme. Thanks, @afizesan for helping pinpoint the issue. +* Fix: Update the way the React app is loaded to suppress React 18+ warnings. +* Tweak: Bumped the plugin's minimum required WordPress version to 6.0+ for best compatibility with new React components in UI. + = 2.0.6 = Fix: The release corrects the paths used in plugin file includes and requires. The unnecessary forward slashes at the start of each file path have been removed. This change ensures proper file inclusion and requirement, avoiding potential issues with file not found errors. diff --git a/src/admin.js b/src/admin.js index 06d2c65..df29f4e 100644 --- a/src/admin.js +++ b/src/admin.js @@ -1,15 +1,14 @@ import './admin.scss'; -import { Button, Dashicon, Modal, Popover, Spinner } from '@wordpress/components'; -import { render, useEffect, useState } from '@wordpress/element'; +import { Button, Dashicon, Modal, Spinner } from '@wordpress/components'; +import { createRoot, useEffect, useState } from '@wordpress/element'; import { __, _n, sprintf } from '@wordpress/i18n'; import domReady from '@wordpress/dom-ready'; import { decodeEntities } from '@wordpress/html-entities'; -import { getQueryArgs } from '@wordpress/url'; +import { addQueryArgs, getQueryArgs } from '@wordpress/url'; import ExpandableText from './ExpandableText'; import TrunkPopover from './TrunkPopover'; const AdminPage = () => { - const [ isLoading, setIsLoading ] = useState( true ); const [ rollbackInfo, setRollbackInfo ] = useState( false ); const [ imageUrl, setImageUrl ] = useState( null ); @@ -25,8 +24,10 @@ const AdminPage = () => { const closeChangelogModal = () => setIsChangelogModalOpen( false ); useEffect( () => { - - let restUrl = `${wprData.restUrl}wp-rollback/v1/fetch-info/?type=${queryArgs.type}&slug=${queryArgs.type === 'theme' ? queryArgs.theme_file : queryArgs.plugin_slug}`; + let restUrl = addQueryArgs( wprData.restUrl + 'wp-rollback/v1/fetch-info/', { + type: queryArgs.type, + slug: queryArgs.type === 'theme' ? queryArgs.theme_file : queryArgs.plugin_slug, + } ); const headers = new Headers( { 'X-WP-Nonce': wprData.restApiNonce, // Assuming nonce is stored in wprData.nonce @@ -43,50 +44,50 @@ const AdminPage = () => { } ); }, [ wprData ] ); - useEffect(() => { + useEffect( () => { const checkAndSetImage = async () => { - if (rollbackInfo && rollbackInfo.slug) { - const sizes = ['icon-256x256', 'icon-128x128', 'icon']; - const extensions = ['png', 'jpg', 'gif', 'svg']; - - for (let size of sizes) { - for (let ext of extensions) { - const url = `https://ps.w.org/${rollbackInfo.slug}/assets/${size}.${ext}`; - const exists = await checkImage(url); - if (exists) { - setImageUrl(url); + if ( rollbackInfo && rollbackInfo.slug ) { + const sizes = [ 'icon-256x256', 'icon-128x128', 'icon' ]; + const extensions = [ 'png', 'jpg', 'gif', 'svg' ]; + + for ( let size of sizes ) { + for ( let ext of extensions ) { + const url = `https://ps.w.org/${ rollbackInfo.slug }/assets/${ size }.${ ext }`; + const exists = await checkImage( url ); + if ( exists ) { + setImageUrl( url ); return; } } } - setImageUrl(wprData.avatarFallback); + setImageUrl( wprData.avatarFallback ); } }; checkAndSetImage(); - }, [rollbackInfo]); + }, [ rollbackInfo ] ); - function checkImage(url) { - return new Promise((resolve, reject) => { + function checkImage( url ) { + return new Promise( ( resolve, reject ) => { var img = new Image(); - img.onload = () => resolve(true); - img.onerror = () => resolve(false); + img.onload = () => resolve( true ); + img.onerror = () => resolve( false ); img.src = url; - }); + } ); } if ( isLoading ) { return ( -
-
-
+
+
+
-

{__( 'Loading...', 'wp-rollback' )}

+

{ __( 'Loading...', 'wp-rollback' ) }

@@ -96,17 +97,16 @@ const AdminPage = () => { // output error message if one is found in the API response if ( rollbackInfo.message ) { return ( -
-
-

{rollbackInfo.code}

-

{rollbackInfo.message}

+
+
+

{ rollbackInfo.code }

+

{ rollbackInfo.message }

); } function getTimeAgo( dateString ) { - // Convert to 24-hour format and remove 'GMT' let adjustedDateString = dateString.replace( 'am', ' AM' ).replace( 'pm', ' PM' ).replace( ' GMT', '' ); adjustedDateString = new Date( adjustedDateString ).toLocaleString( 'en-US', { timeZone: 'GMT' } ); @@ -125,289 +125,401 @@ const AdminPage = () => { return sprintf( _n( '%s second ago', '%s seconds ago', diffInSeconds, 'wp-rollback' ), diffInSeconds ); } else if ( diffInSeconds < 3600 ) { // translators: %s Number of minutes. - return sprintf( _n( '%s minute ago', '%s minutes ago', Math.floor( diffInSeconds / 60 ), 'wp-rollback' ), Math.floor( diffInSeconds / 60 ) ); + return sprintf( + _n( '%s minute ago', '%s minutes ago', Math.floor( diffInSeconds / 60 ), 'wp-rollback' ), + Math.floor( diffInSeconds / 60 ) + ); } else if ( diffInSeconds < 86400 ) { // translators: %s Number of hours. - return sprintf( _n( '%s hour ago', '%s hours ago', Math.floor( diffInSeconds / 3600 ), 'wp-rollback' ), Math.floor( diffInSeconds / 3600 ) ); - } else if ( diffInSeconds < 2592000 ) { // 30 days + return sprintf( + _n( '%s hour ago', '%s hours ago', Math.floor( diffInSeconds / 3600 ), 'wp-rollback' ), + Math.floor( diffInSeconds / 3600 ) + ); + } else if ( diffInSeconds < 2592000 ) { + // 30 days // translators: %s Number of days. - return sprintf( _n( '%s day ago', '%s days ago', Math.floor( diffInSeconds / 86400 ), 'wp-rollback' ), Math.floor( diffInSeconds / 86400 ) ); - } else if ( diffInSeconds < 31536000 ) { // 365 days + return sprintf( + _n( '%s day ago', '%s days ago', Math.floor( diffInSeconds / 86400 ), 'wp-rollback' ), + Math.floor( diffInSeconds / 86400 ) + ); + } else if ( diffInSeconds < 31536000 ) { + // 365 days // translators: %s Number of monthes. - return sprintf( _n( '%s month ago', '%s months ago', Math.floor( diffInSeconds / 2592000 ), 'wp-rollback' ), Math.floor( diffInSeconds / 2592000 ) ); + return sprintf( + _n( '%s month ago', '%s months ago', Math.floor( diffInSeconds / 2592000 ), 'wp-rollback' ), + Math.floor( diffInSeconds / 2592000 ) + ); } else { // translators: %s Number of years. - return sprintf( _n( '%s year ago', '%s years ago', Math.floor( diffInSeconds / 31536000 ), 'wp-rollback' ), Math.floor( diffInSeconds / 31536000 ) ); + return sprintf( + _n( '%s year ago', '%s years ago', Math.floor( diffInSeconds / 31536000 ), 'wp-rollback' ), + Math.floor( diffInSeconds / 31536000 ) + ); } } return ( -
-
-
-

{__( 'WP Rollback', 'wp-rollback' )}

- {'WP +
+
+
+

{ __( 'WP Rollback', 'wp-rollback' ) }

+ + { +
-

{__( 'Select which version you would like to rollback to from the releases listed below.', 'wp-rollback' )}

+

+ { __( + 'Select which version you would like to rollback to from the releases listed below.', + 'wp-rollback' + ) } +

- {rollbackInfo.banners && queryArgs.type === 'plugin' && ( rollbackInfo.banners.high || rollbackInfo.banners.low ) && ( -
- {rollbackInfo.name}/ -
- )} + { rollbackInfo.banners && + queryArgs.type === 'plugin' && + ( rollbackInfo.banners.high || rollbackInfo.banners.low ) && ( +
+ { +
+ ) }
- - {rollbackInfo.screenshot_url && queryArgs.type === 'theme' && ( + { rollbackInfo.screenshot_url && queryArgs.type === 'theme' && (
- {rollbackInfo.name}/ + {
- )} - - {imageUrl && queryArgs.type === 'plugin' && ( -
- {rollbackInfo.name}/ + ) } + + { imageUrl && queryArgs.type === 'plugin' && ( +
+ {
- - )} - -
-

- {queryArgs.type === 'plugin' && ( - +

+ { queryArgs.type === 'plugin' && ( + - {decodeEntities( rollbackInfo.name )} - + { decodeEntities( rollbackInfo.name ) } + - )} - {queryArgs.type === 'theme' && ( - - {decodeEntities( rollbackInfo.name )} - + alt={ sprintf( + __( 'View %s on WordPress.org', 'wp-rollback' ), + rollbackInfo.name + ) } + > + { decodeEntities( rollbackInfo.name ) } + - )} - + ) }

- {queryArgs.type === 'theme' && rollbackInfo.sections.description && ( -
- + { queryArgs.type === 'theme' && rollbackInfo.sections.description && ( +
+
- )} - -
-
{__( 'Installed version:', 'wp-rollback' )}{' '} - {queryArgs.current_version}
- - {queryArgs.type === 'plugin' && ( -
- {__( 'Plugin author:', 'wp-rollback' )}{' '} - - + ) } + +
+
+ + { __( 'Installed version:', 'wp-rollback' ) }{ ' ' } + { queryArgs.current_version } + +
+ + { queryArgs.type === 'plugin' && ( +
+ + { __( 'Plugin author:', 'wp-rollback' ) }{ ' ' } +
- )} + ) }
-
-
- {queryArgs.type === 'theme' && ( -
-

{__( 'Theme Author', 'wp-rollback' )}

-
- -
{rollbackInfo.author.display_name} +
+ { queryArgs.type === 'theme' && ( +
+

{ __( 'Theme Author', 'wp-rollback' ) }

+
- )} - - {queryArgs.type === 'plugin' && ( -
-
- + ) } + + { queryArgs.type === 'plugin' && ( +
+
+
-

{__( 'Last Updated', 'wp-rollback' )}

-
- - {getTimeAgo( rollbackInfo.last_updated )} +

{ __( 'Last Updated', 'wp-rollback' ) }

+
+ + + { getTimeAgo( rollbackInfo.last_updated ) } +
- )} + ) }
-
- {Object.keys( rollbackInfo.versions ) - .sort((a, b) => { - if (a === 'trunk') return 1; // Always places 'trunk' at the end - if (b === 'trunk') return -1; // Always places 'trunk' at the end - return b.localeCompare(a, undefined, { +
+ { Object.keys( rollbackInfo.versions ) + .sort( ( a, b ) => { + if ( a === 'trunk' ) { + return 1; + } // Always places 'trunk' at the end + if ( b === 'trunk' ) { + return -1; + } // Always places 'trunk' at the end + return b.localeCompare( a, undefined, { numeric: true, sensitivity: 'base', - }); - }) + } ); + } ) .map( ( version, index ) => ( -
-
-
-
- - +
+ +
- {isChangelogModalOpen && ( + { isChangelogModalOpen && ( } + title={ __( 'Plugin Changelog', 'wp-rollback' ) } + onRequestClose={ closeChangelogModal } + disabled={ rollbackVersion === false } + className={ 'wpr-modal wpr-modal__changelog' } + icon={ } > -
+
- )} + ) } - {isConfirmModalOpen && ( + { isConfirmModalOpen && ( } + title={ __( 'Are you sure you want to proceed?', 'wp-rollback' ) } + onRequestClose={ closeConfirmModal } + disabled={ rollbackVersion === false } + className={ 'wpr-modal' } + icon={ } > -

${rollbackInfo.name}`, - `${rollbackVersion}`, - ), - }}>

+

${ rollbackInfo.name }`, + `${ rollbackVersion }` + ), + } } + >

- - - - - - - - - - - - + + + + + + + + + + + +
- -
- - {queryArgs.current_version} -
- - {rollbackVersion}
+ + + +
+ + + { queryArgs.current_version } +
+ + + { rollbackVersion } +
-
Notice: We strongly recommend you create a complete backup of your WordPress files and database prior to performing a rollback. We are not responsible for any misuse, deletions, white screens, fatal errors, or any other issue resulting from the use of this plugin.

', 'wp-rollback' ) }}/> +
Notice: We strongly recommend you create a complete backup of your WordPress files and database prior to performing a rollback. We are not responsible for any misuse, deletions, white screens, fatal errors, or any other issue resulting from the use of this plugin.

', + 'wp-rollback' + ), + } } + /> -
- - - + + + + - {queryArgs.type === 'plugin' && ( + { queryArgs.type === 'plugin' && (
- - - + + +
- )} - {queryArgs.type === 'theme' && ( + ) } + { queryArgs.type === 'theme' && (
- - + +
- )} - - - - -
- - + ) } + + + + +
+ +
- )} - + ) }
- ); - }; -domReady( function() { - if ( document.getElementById( 'root-wp-rollback-admin' ) ) { - render( , document.getElementById( 'root-wp-rollback-admin' ) ); +domReady( function () { + const container = document.getElementById( 'root-wp-rollback-admin' ); + if ( ! container ) { + return; + } + + const component = ; + + // Use createRoot if available, otherwise fallback to ReactDOM.render + if ( createRoot ) { + createRoot( container ).render( component ); + } else { + ReactDOM.render( component, container ); } } ); diff --git a/wp-rollback.php b/wp-rollback.php index acf2279..53ab4ce 100644 --- a/wp-rollback.php +++ b/wp-rollback.php @@ -5,7 +5,7 @@ * Description: Rollback (or forward) any WordPress.org plugin, theme or block like a boss. * Author: WP Rollback * Author URI: https://wprollback.com/ - * Version: 2.0.6 + * Version: 2.0.7 * Text Domain: wp-rollback * Domain Path: /languages *