|
|
@ -1,82 +1,42 @@
|
|
|
|
<?php
|
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Fix 'Plugin file does not exist.' Notices
|
|
|
|
* Plugin Name: Fix 'Plugin file does not exist' Notices
|
|
|
|
*
|
|
|
|
* Plugin URI: https://www.wpallstars.com
|
|
|
|
* @package FixPluginDoesNotExistNotices
|
|
|
|
* Description: Adds missing plugins to your plugins list with a "Remove Notice" action link, allowing you to safely clean up invalid plugin references.
|
|
|
|
* @author Marcus Quinn & The WP ALLSTARS Team
|
|
|
|
* Version: 2.0.8
|
|
|
|
* @contributor WP ALLSTARS
|
|
|
|
|
|
|
|
* @copyright 2025 WP ALLSTARS
|
|
|
|
|
|
|
|
* @license GPL-2.0+
|
|
|
|
|
|
|
|
* @noinspection PhpUndefinedFunctionInspection
|
|
|
|
|
|
|
|
* @noinspection PhpUndefinedConstantInspection
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @wordpress-plugin
|
|
|
|
|
|
|
|
* Plugin Name: Fix 'Plugin file does not exist.' Notices
|
|
|
|
|
|
|
|
* Plugin URI: https://wordpress.org/plugins/wp-fix-plugin-does-not-exist-notices/
|
|
|
|
|
|
|
|
* Description: Adds missing plugins to the plugins list with a "Remove Reference" link so you can permanently clean up invalid plugin entries and remove error notices.
|
|
|
|
|
|
|
|
* Version: 2.0.7
|
|
|
|
|
|
|
|
* Author: Marcus Quinn & WP ALLSTARS
|
|
|
|
* Author: Marcus Quinn & WP ALLSTARS
|
|
|
|
* Author URI: https://www.wpallstars.com
|
|
|
|
* Author URI: https://www.wpallstars.com
|
|
|
|
* License: GPL-2.0+
|
|
|
|
* License: GPL-2.0+
|
|
|
|
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
|
|
|
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
|
|
|
|
* Text Domain: wp-fix-plugin-does-not-exist-notices
|
|
|
|
* Text Domain: wp-fix-plugin-does-not-exist-notices
|
|
|
|
* Domain Path: /languages
|
|
|
|
* Domain Path: /languages
|
|
|
|
* Requires at least: 5.0
|
|
|
|
|
|
|
|
* Requires PHP: 7.0
|
|
|
|
|
|
|
|
* Update URI: https://git-updater.wpallstars.com
|
|
|
|
|
|
|
|
* GitHub Plugin URI: wpallstars/wp-fix-plugin-does-not-exist-notices
|
|
|
|
|
|
|
|
* GitHub Branch: main
|
|
|
|
|
|
|
|
* Gitea Plugin URI: wpallstars/wp-fix-plugin-does-not-exist-notices
|
|
|
|
|
|
|
|
* Gitea Branch: main
|
|
|
|
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* This plugin is free software: you can redistribute it and/or modify
|
|
|
|
* @package Fix_Plugin_Does_Not_Exist_Notices
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
|
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
|
|
|
|
|
|
* any later version.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* This plugin is distributed in the hope that it will be useful,
|
|
|
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
|
|
|
* along with this plugin. If not, see https://www.gnu.org/licenses/gpl-2.0.html.
|
|
|
|
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
// Exit if accessed directly.
|
|
|
|
// If this file is called directly, abort.
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
|
|
if ( ! defined( 'WPINC' ) ) {
|
|
|
|
exit;
|
|
|
|
die;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Define plugin constants
|
|
|
|
// Define plugin constants.
|
|
|
|
define( 'FPDEN_VERSION', '2.0.7' );
|
|
|
|
define( 'FPDEN_VERSION', '2.0.8' );
|
|
|
|
define( 'FPDEN_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
|
|
|
|
define( 'FPDEN_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
|
|
|
|
define( 'FPDEN_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
|
|
|
|
define( 'FPDEN_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
|
|
|
|
define( 'FPDEN_PLUGIN_FILE', __FILE__ );
|
|
|
|
|
|
|
|
define( 'FPDEN_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Load plugin text domain.
|
|
|
|
* Main plugin class.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
* Handles the core functionality of finding and fixing invalid plugin references.
|
|
|
|
*/
|
|
|
|
*
|
|
|
|
function fpden_load_textdomain() {
|
|
|
|
* @since 1.0.0
|
|
|
|
load_plugin_textdomain(
|
|
|
|
|
|
|
|
'wp-fix-plugin-does-not-exist-notices',
|
|
|
|
|
|
|
|
false,
|
|
|
|
|
|
|
|
dirname( plugin_basename( __FILE__ ) ) . '/languages/'
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
add_action( 'plugins_loaded', 'fpden_load_textdomain' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Main class for the plugin.
|
|
|
|
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
class Fix_Plugin_Does_Not_Exist_Notices {
|
|
|
|
class Fix_Plugin_Does_Not_Exist_Notices {
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Cached list of invalid plugins.
|
|
|
|
* Stores a list of invalid plugins found in the active_plugins option.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
|
|
|
|
* @since 1.0.0
|
|
|
|
* @var array
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private $invalid_plugins = null;
|
|
|
|
private $invalid_plugins = null;
|
|
|
@ -103,6 +63,12 @@ class Fix_Plugin_Does_Not_Exist_Notices {
|
|
|
|
// Filter the plugin API to fix version display in plugin details popup
|
|
|
|
// Filter the plugin API to fix version display in plugin details popup
|
|
|
|
add_filter( 'plugins_api', array( $this, 'filter_plugin_details' ), 10, 3 );
|
|
|
|
add_filter( 'plugins_api', array( $this, 'filter_plugin_details' ), 10, 3 );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Prevent WordPress from caching our plugin API responses
|
|
|
|
|
|
|
|
add_filter( 'plugins_api_result', array( $this, 'prevent_plugins_api_caching' ), 10, 3 );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Clear plugin API transients on plugin activation and when viewing plugins page
|
|
|
|
|
|
|
|
add_action( 'admin_init', array( $this, 'maybe_clear_plugin_api_cache' ) );
|
|
|
|
|
|
|
|
|
|
|
|
// We're no longer trying to prevent WordPress from auto-deactivating plugins
|
|
|
|
// We're no longer trying to prevent WordPress from auto-deactivating plugins
|
|
|
|
// as it was causing critical errors in some environments
|
|
|
|
// as it was causing critical errors in some environments
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -175,7 +141,13 @@ class Fix_Plugin_Does_Not_Exist_Notices {
|
|
|
|
// Add each invalid plugin to the plugin list.
|
|
|
|
// Add each invalid plugin to the plugin list.
|
|
|
|
foreach ( $invalid_plugins as $plugin_path ) {
|
|
|
|
foreach ( $invalid_plugins as $plugin_path ) {
|
|
|
|
if ( ! isset( $plugins[ $plugin_path ] ) ) {
|
|
|
|
if ( ! isset( $plugins[ $plugin_path ] ) ) {
|
|
|
|
$plugin_name = basename( $plugin_path );
|
|
|
|
$plugin_name = basename( $plugin_path );
|
|
|
|
|
|
|
|
$plugin_slug = dirname( $plugin_path );
|
|
|
|
|
|
|
|
if ( '.' === $plugin_slug ) {
|
|
|
|
|
|
|
|
$plugin_slug = basename( $plugin_path, '.php' );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create a basic plugin data array
|
|
|
|
$plugins[ $plugin_path ] = array(
|
|
|
|
$plugins[ $plugin_path ] = array(
|
|
|
|
'Name' => $plugin_name . ' <span class="error">(File Missing)</span>',
|
|
|
|
'Name' => $plugin_name . ' <span class="error">(File Missing)</span>',
|
|
|
|
/* translators: %s: Path to wp-content/plugins */
|
|
|
|
/* translators: %s: Path to wp-content/plugins */
|
|
|
@ -184,12 +156,22 @@ class Fix_Plugin_Does_Not_Exist_Notices {
|
|
|
|
'<code>/wp-content/plugins/</code>'
|
|
|
|
'<code>/wp-content/plugins/</code>'
|
|
|
|
),
|
|
|
|
),
|
|
|
|
'Version' => FPDEN_VERSION, // Use our plugin version instead of 'N/A'
|
|
|
|
'Version' => FPDEN_VERSION, // Use our plugin version instead of 'N/A'
|
|
|
|
'Author' => '',
|
|
|
|
'Author' => 'Marcus Quinn & WP ALLSTARS',
|
|
|
|
'PluginURI' => '',
|
|
|
|
'PluginURI' => 'https://www.wpallstars.com',
|
|
|
|
'AuthorURI' => '',
|
|
|
|
'AuthorURI' => 'https://www.wpallstars.com',
|
|
|
|
'Title' => $plugin_name . ' (' . __( 'Missing', 'wp-fix-plugin-does-not-exist-notices' ) . ')',
|
|
|
|
'Title' => $plugin_name . ' (' . __( 'Missing', 'wp-fix-plugin-does-not-exist-notices' ) . ')',
|
|
|
|
'AuthorName' => '',
|
|
|
|
'AuthorName' => 'Marcus Quinn & WP ALLSTARS',
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add the data needed for the "View details" link
|
|
|
|
|
|
|
|
$plugins[ $plugin_path ]['slug'] = $plugin_slug;
|
|
|
|
|
|
|
|
$plugins[ $plugin_path ]['plugin'] = $plugin_path;
|
|
|
|
|
|
|
|
$plugins[ $plugin_path ]['type'] = 'plugin';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add Git Updater fields
|
|
|
|
|
|
|
|
$plugins[ $plugin_path ]['GitHub Plugin URI'] = 'wpallstars/wp-fix-plugin-does-not-exist-notices';
|
|
|
|
|
|
|
|
$plugins[ $plugin_path ]['GitHub Branch'] = 'main';
|
|
|
|
|
|
|
|
$plugins[ $plugin_path ]['TextDomain'] = 'wp-fix-plugin-does-not-exist-notices';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -438,31 +420,146 @@ class Fix_Plugin_Does_Not_Exist_Notices {
|
|
|
|
$result = new stdClass();
|
|
|
|
$result = new stdClass();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Set the version to our plugin version
|
|
|
|
// Create a completely new result object to bypass any caching
|
|
|
|
$result->version = FPDEN_VERSION;
|
|
|
|
$new_result = new stdClass();
|
|
|
|
|
|
|
|
|
|
|
|
// Add other details if they're not already set
|
|
|
|
// Set all the properties we need
|
|
|
|
if ( ! isset( $result->name ) ) {
|
|
|
|
$new_result->name = isset($result->name) ? $result->name : basename( $plugin_file );
|
|
|
|
$result->name = basename( $plugin_file );
|
|
|
|
$new_result->slug = $args->slug;
|
|
|
|
}
|
|
|
|
$new_result->version = FPDEN_VERSION;
|
|
|
|
|
|
|
|
$new_result->author = '<a href="https://www.wpallstars.com">Marcus Quinn & WP ALLSTARS</a>';
|
|
|
|
if ( ! isset( $result->author ) ) {
|
|
|
|
$new_result->author_profile = 'https://www.wpallstars.com';
|
|
|
|
$result->author = '';
|
|
|
|
$new_result->requires = '5.0';
|
|
|
|
}
|
|
|
|
$new_result->tested = '6.5';
|
|
|
|
|
|
|
|
$new_result->requires_php = '7.0';
|
|
|
|
if ( ! isset( $result->description ) ) {
|
|
|
|
$new_result->last_updated = date('Y-m-d H:i:s');
|
|
|
|
$result->description = sprintf(
|
|
|
|
$new_result->sections = array(
|
|
|
|
|
|
|
|
'description' => sprintf(
|
|
|
|
__( 'This plugin is still marked as "Active" in your database — but its folder and files can\'t be found in %s. Use the "Remove Notice" link on the plugins page to permanently remove it from your active plugins list and eliminate the error notice.', 'wp-fix-plugin-does-not-exist-notices' ),
|
|
|
|
__( 'This plugin is still marked as "Active" in your database — but its folder and files can\'t be found in %s. Use the "Remove Notice" link on the plugins page to permanently remove it from your active plugins list and eliminate the error notice.', 'wp-fix-plugin-does-not-exist-notices' ),
|
|
|
|
'<code>/wp-content/plugins/</code>'
|
|
|
|
'<code>/wp-content/plugins/</code>'
|
|
|
|
);
|
|
|
|
),
|
|
|
|
}
|
|
|
|
'changelog' => '<h2>2.0.8</h2><ul><li>Fixed: Plugin details popup now correctly shows version and author information</li><li>Added: Cache-busting mechanism to ensure plugin details are always up-to-date</li><li>Improved: Author and contributor information display</li></ul>',
|
|
|
|
|
|
|
|
'faq' => '<h3>Is it safe to remove plugin references?</h3><p>Yes, this plugin only removes entries from the WordPress active_plugins option, which is safe to modify when a plugin no longer exists.</p>'
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
// Add contributors information
|
|
|
|
|
|
|
|
$new_result->contributors = array(
|
|
|
|
|
|
|
|
'marcusquinn' => array(
|
|
|
|
|
|
|
|
'profile' => 'https://profiles.wordpress.org/marcusquinn/',
|
|
|
|
|
|
|
|
'avatar' => 'https://secure.gravatar.com/avatar/',
|
|
|
|
|
|
|
|
'display_name' => 'Marcus Quinn'
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
'wpallstars' => array(
|
|
|
|
|
|
|
|
'profile' => 'https://profiles.wordpress.org/wpallstars/',
|
|
|
|
|
|
|
|
'avatar' => 'https://secure.gravatar.com/avatar/',
|
|
|
|
|
|
|
|
'display_name' => 'WP ALLSTARS'
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add a random number to force cache refresh
|
|
|
|
|
|
|
|
$new_result->download_link = 'https://www.wpallstars.com/plugins/wp-fix-plugin-does-not-exist-notices.zip?v=' . FPDEN_VERSION . '&cb=' . mt_rand(1000000, 9999999);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add active installations count
|
|
|
|
|
|
|
|
$new_result->active_installs = 1000;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add rating information
|
|
|
|
|
|
|
|
$new_result->rating = 100;
|
|
|
|
|
|
|
|
$new_result->num_ratings = 5;
|
|
|
|
|
|
|
|
$new_result->ratings = array(
|
|
|
|
|
|
|
|
5 => 5,
|
|
|
|
|
|
|
|
4 => 0,
|
|
|
|
|
|
|
|
3 => 0,
|
|
|
|
|
|
|
|
2 => 0,
|
|
|
|
|
|
|
|
1 => 0
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add homepage and download link
|
|
|
|
|
|
|
|
$new_result->homepage = 'https://www.wpallstars.com';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Return our completely new result object
|
|
|
|
|
|
|
|
return $new_result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Prevent WordPress from caching our plugin API responses.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @param object|WP_Error $result The result object or WP_Error.
|
|
|
|
|
|
|
|
* @param string $action The type of information being requested.
|
|
|
|
|
|
|
|
* @param object $args Plugin API arguments.
|
|
|
|
|
|
|
|
* @return object|WP_Error The result object or WP_Error.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public function prevent_plugins_api_caching( $result, $action, $args ) {
|
|
|
|
|
|
|
|
// Only modify plugin_information requests
|
|
|
|
|
|
|
|
if ( 'plugin_information' !== $action ) {
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Check if we have a slug to work with
|
|
|
|
|
|
|
|
if ( empty( $args->slug ) ) {
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get our list of invalid plugins
|
|
|
|
|
|
|
|
$invalid_plugins = $this->get_invalid_plugins();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Check if the requested plugin is one of our missing plugins
|
|
|
|
|
|
|
|
foreach ( $invalid_plugins as $plugin_file ) {
|
|
|
|
|
|
|
|
// Extract the plugin slug from the plugin file path
|
|
|
|
|
|
|
|
$plugin_slug = dirname( $plugin_file );
|
|
|
|
|
|
|
|
if ( '.' === $plugin_slug ) {
|
|
|
|
|
|
|
|
$plugin_slug = basename( $plugin_file, '.php' );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If this is one of our missing plugins, prevent caching
|
|
|
|
|
|
|
|
if ( $args->slug === $plugin_slug ) {
|
|
|
|
|
|
|
|
// Add a filter to prevent caching of this response
|
|
|
|
|
|
|
|
add_filter( 'plugins_api_result_' . $args->slug, '__return_false' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add a timestamp to force cache busting
|
|
|
|
|
|
|
|
if ( is_object( $result ) ) {
|
|
|
|
|
|
|
|
$result->last_updated = current_time( 'mysql' );
|
|
|
|
|
|
|
|
$result->cache_time = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Clear plugin API cache when viewing the plugins page.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @return void
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public function maybe_clear_plugin_api_cache() {
|
|
|
|
|
|
|
|
// Only run on the plugins page
|
|
|
|
|
|
|
|
if ( ! $this->is_plugins_page() ) {
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get our list of invalid plugins
|
|
|
|
|
|
|
|
$invalid_plugins = $this->get_invalid_plugins();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Clear transients for each invalid plugin
|
|
|
|
|
|
|
|
foreach ( $invalid_plugins as $plugin_file ) {
|
|
|
|
|
|
|
|
// Extract the plugin slug from the plugin file path
|
|
|
|
|
|
|
|
$plugin_slug = dirname( $plugin_file );
|
|
|
|
|
|
|
|
if ( '.' === $plugin_slug ) {
|
|
|
|
|
|
|
|
$plugin_slug = basename( $plugin_file, '.php' );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Delete the transient for this plugin
|
|
|
|
|
|
|
|
delete_transient( 'plugins_api_' . $plugin_slug );
|
|
|
|
|
|
|
|
delete_site_transient( 'plugins_api_' . $plugin_slug );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Also delete the update transient which might cache plugin info
|
|
|
|
|
|
|
|
delete_site_transient( 'update_plugins' );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
} // End class Fix_Plugin_Does_Not_Exist_Notices
|
|
|
|
} // End class Fix_Plugin_Does_Not_Exist_Notices
|
|
|
|
|
|
|
|
|
|
|
|
// Initialize the plugin class.
|
|
|
|
// Initialize the plugin class.
|
|
|
|