diff --git a/.ai-assistant.md b/.ai-assistant.md new file mode 100644 index 0000000..fdd9c7a --- /dev/null +++ b/.ai-assistant.md @@ -0,0 +1,195 @@ +# AI Assistant Guide for Fix Plugin Does Not Exist Notices + +This guide helps AI assistants understand the project structure, workflows, and best practices for this repository. + +## Project Overview + +- **Plugin Name**: Fix 'Plugin file does not exist.' Notices +- **Repository**: https://github.com/wpallstars/fix-plugin-does-not-exist-notices +- **Description**: WordPress plugin that adds missing plugins to the plugins list with a "Remove Reference" link to clean up invalid plugin entries and remove error notices. + +## Version Management + +### Version Numbering Convention + +We follow [Semantic Versioning](https://semver.org/): +- **MAJOR.MINOR.PATCH** (e.g., 1.6.0) + - **MAJOR**: Breaking changes + - **MINOR**: New features, non-breaking + - **PATCH**: Bug fixes, non-breaking + +### When to Increment Version Numbers + +- **PATCH** (1.6.0 → 1.6.1): + - Bug fixes + - Small text changes + - Minor improvements that don't add new features + +- **MINOR** (1.6.0 → 1.7.0): + - New features + - Significant improvements to existing functionality + - Deprecation of features (but not removal) + +- **MAJOR** (1.6.0 → 2.0.0): + - Breaking changes + - Removal of features + - Major architectural changes + +### Version Update Checklist + +When updating the version number, always update these files: +1. `fix-plugin-does-not-exist-notices.php` (Plugin header) +2. `CHANGELOG.md` (Add new version section) +3. `readme.txt` (Stable tag and Changelog section) +4. `README.md` (Update Changelog section to match readme.txt) +5. Update `FPDEN_VERSION` constant in the main plugin file + +**IMPORTANT**: Always ensure README.md is kept in sync with readme.txt for consistency across platforms. + +## Git Workflow + +### Branch Naming Convention + +- Feature branches: `feature/descriptive-name` +- Bug fix branches: `fix/issue-description` +- Release branches: `v{MAJOR}.{MINOR}.{PATCH}` + +### Commit Message Guidelines + +- Use present tense ("Add feature" not "Added feature") +- Start with a verb +- Keep the first line under 50 characters +- Reference issues when relevant: "Fix #123: Resolve plugin detection issue" + +### Pre-Release Checklist + +Before creating a new release, verify the following: + +- [ ] Determine the correct version increment (MAJOR, MINOR, or PATCH) based on the changes +- [ ] Ensure all changes are documented in CHANGELOG.md +- [ ] Verify all code changes are tested and working correctly +- [ ] Check that all files are properly formatted and follow WordPress coding standards +- [ ] Ensure Git Updater configuration is correct (if applicable) + +### Release Process + +1. Create a new branch for the version: `git checkout -b v{MAJOR}.{MINOR}.{PATCH}` +2. Update version numbers in ALL required files: + - `fix-plugin-does-not-exist-notices.php` (Plugin header) + - `FPDEN_VERSION` constant in the main plugin file + - `readme.txt` (Stable tag) + - `README.md` (Ensure changelog is updated) + - Any other files that reference the version number +3. Update CHANGELOG.md with all changes +4. Update readme.txt changelog section +5. Update README.md changelog section to match readme.txt +6. Commit changes: `git commit -m "Prepare release v{MAJOR}.{MINOR}.{PATCH}"` +7. Push branch to all remotes: + ``` + git push github HEAD:v{MAJOR}.{MINOR}.{PATCH} + git push gitea HEAD:v{MAJOR}.{MINOR}.{PATCH} + ``` +8. Create and push a tag to trigger the GitHub Actions workflow: + ``` + git tag -a v{MAJOR}.{MINOR}.{PATCH} -m "Release version {MAJOR}.{MINOR}.{PATCH}" + git push github refs/tags/v{MAJOR}.{MINOR}.{PATCH} + git push gitea refs/tags/v{MAJOR}.{MINOR}.{PATCH} + ``` +9. Verify the GitHub Actions workflow completes successfully + +## Build Process + +The build process is handled by `build.sh`: +1. Updates version numbers +2. Installs composer dependencies +3. Copies files to build directory +4. Creates ZIP file + +To manually build the plugin: +``` +./build.sh {MAJOR}.{MINOR}.{PATCH} +``` + +## Remote Repositories + +The plugin is hosted on multiple repositories: +- GitHub: https://github.com/wpallstars/fix-plugin-does-not-exist-notices +- Gitea: https://gitea.wpallstars.com/wpallstars/fix-plugin-does-not-exist-notices +- WordPress.org: https://wordpress.org/plugins/fix-plugin-does-not-exist-notices/ + +Always push changes to all remotes to keep them in sync. + +## GitHub Actions + +The repository uses GitHub Actions for automated builds and deployments: +- Triggered by tags matching the pattern `v*` +- Builds the plugin +- Creates a GitHub release +- Deploys to WordPress.org + +## Testing Guidelines + +Before releasing: +1. Test with the latest WordPress version +2. Test with PHP 7.0+ (minimum supported version) +3. Verify all features work as expected +4. Check for any PHP warnings or notices + +## Common Tasks for AI Assistants + +### Creating a New Release + +``` +# 1. Create a new branch +git checkout -b v1.7.0 + +# 2. Update version numbers in ALL required files +# - fix-plugin-does-not-exist-notices.php +# - CHANGELOG.md +# - readme.txt +# - README.md +# - FPDEN_VERSION constant + +# 3. Commit changes +git add . +git commit -m "Prepare release v1.7.0" + +# 4. Push to remotes +git push github HEAD:v1.7.0 +git push gitea HEAD:v1.7.0 + +# 5. Create and push tag +git tag -a v1.7.0 -m "Release version 1.7.0" +git push github refs/tags/v1.7.0 +git push gitea refs/tags/v1.7.0 +``` + +### Adding a New Feature + +``` +# 1. Create feature branch +git checkout -b feature/new-feature-name + +# 2. Make changes and commit +git add . +git commit -m "Add new feature" + +# 3. Push to remotes +git push github HEAD:feature/new-feature-name +git push gitea HEAD:feature/new-feature-name +``` + +### Fixing a Bug + +``` +# 1. Create bugfix branch +git checkout -b fix/bug-description + +# 2. Make changes and commit +git add . +git commit -m "Fix #123: Fix bug description" + +# 3. Push to remotes +git push github HEAD:fix/bug-description +git push gitea HEAD:fix/bug-description +``` diff --git a/.github/ai-workflows/bug-fixing.md b/.github/ai-workflows/bug-fixing.md new file mode 100644 index 0000000..3c5a7be --- /dev/null +++ b/.github/ai-workflows/bug-fixing.md @@ -0,0 +1,160 @@ +# Bug Fixing Guide for AI Assistants + +This document provides guidance for AI assistants to help with bug fixing for the Fix Plugin Does Not Exist Notices plugin. + +## Bug Fixing Workflow + +### 1. Create a Bug Fix Branch + +Always start by creating a bug fix branch from the main branch: + +```bash +git checkout main +git pull github main +git checkout -b fix/bug-description +``` + +Use a descriptive name that clearly indicates what bug is being fixed. + +### 2. Understand the Bug + +Before fixing a bug, make sure you understand: + +- What is the expected behavior? +- What is the actual behavior? +- What are the steps to reproduce the bug? +- What is the impact of the bug? +- What is the root cause of the bug? + +### 3. Fix the Bug + +When fixing a bug: + +- Make minimal changes necessary to fix the bug +- Avoid introducing new features while fixing bugs +- Maintain backward compatibility +- Add appropriate comments explaining the fix +- Consider adding tests to prevent regression + +### 4. Update Documentation + +Update relevant documentation to reflect the bug fix: + +- Add a description to CHANGELOG.md under an "Unreleased" section +- Update readme.txt if the bug fix affects user-facing functionality + +### 5. Testing + +Test the bug fix thoroughly: + +- Verify that the bug is fixed +- Ensure no regression in related functionality +- Test with the latest WordPress version +- Test with the minimum supported WordPress version (5.0) +- Test with PHP 7.0+ (minimum supported version) + +### 6. Commit Changes + +Make atomic commits with clear messages: + +```bash +git add . +git commit -m "Fix #123: Brief description of the bug fix" +``` + +If there's an issue number, reference it in the commit message. + +### 7. Push to Remote + +Push the bug fix branch to the remote repositories: + +```bash +git push github HEAD:fix/bug-description +git push gitea HEAD:fix/bug-description +``` + +### 8. Create Pull Request (Optional) + +If the repository uses pull requests for code review, create a pull request from the bug fix branch to the main branch. + +## Determining Version Increment + +After fixing a bug, determine the appropriate version increment: + +- **PATCH** (e.g., 1.6.0 → 1.6.1): For most bug fixes that don't change functionality +- **MINOR** (e.g., 1.6.0 → 1.7.0): For bug fixes that introduce new features or significant changes +- **MAJOR** (e.g., 1.6.0 → 2.0.0): For bug fixes that introduce breaking changes + +## Hotfix Process + +For critical bugs that need immediate fixing in a released version: + +### 1. Create a Hotfix Branch + +```bash +git checkout v{MAJOR}.{MINOR}.{PATCH} +git checkout -b hotfix/v{MAJOR}.{MINOR}.{PATCH+1} +``` + +### 2. Fix the Bug + +Apply the minimal fix necessary to address the critical issue. + +### 3. Update Version Numbers + +Increment the PATCH version and update all version numbers: + +- Main plugin file (fix-plugin-does-not-exist-notices.php) +- FPDEN_VERSION constant +- CHANGELOG.md +- readme.txt + +### 4. Commit and Push + +```bash +git add . +git commit -m "Hotfix: Brief description of the critical bug fix" +git push github HEAD:hotfix/v{MAJOR}.{MINOR}.{PATCH+1} +git push gitea HEAD:hotfix/v{MAJOR}.{MINOR}.{PATCH+1} +``` + +### 5. Create and Push Tag + +```bash +git tag -a v{MAJOR}.{MINOR}.{PATCH+1} -m "Hotfix release version {MAJOR}.{MINOR}.{PATCH+1}" +git push github refs/tags/v{MAJOR}.{MINOR}.{PATCH+1} +git push gitea refs/tags/v{MAJOR}.{MINOR}.{PATCH+1} +``` + +## Common Bug Types and Fixing Strategies + +### WordPress Compatibility Issues + +- Test with the specific WordPress version where the issue occurs +- Check for deprecated functions or hooks +- Review WordPress changelog for relevant changes + +### PHP Compatibility Issues + +- Test with the specific PHP version where the issue occurs +- Check for deprecated PHP functions or features +- Use appropriate polyfills if necessary + +### JavaScript Issues + +- Test in different browsers +- Check for browser console errors +- Consider browser-specific workarounds if necessary + +### CSS Issues + +- Test in different browsers and screen sizes +- Use browser developer tools to inspect elements +- Consider browser-specific workarounds if necessary + +### Database Issues + +- Use proper database prefixing +- Sanitize database inputs +- Use prepared statements for queries +- Consider database version differences diff --git a/.github/ai-workflows/code-review.md b/.github/ai-workflows/code-review.md new file mode 100644 index 0000000..37c09f4 --- /dev/null +++ b/.github/ai-workflows/code-review.md @@ -0,0 +1,163 @@ +# Code Review Guide for AI Assistants + +This document provides guidance for AI assistants to help with code review for the Fix Plugin Does Not Exist Notices plugin. + +## Code Review Checklist + +When reviewing code, check for the following: + +### Functionality + +- [ ] Does the code work as expected? +- [ ] Does it handle edge cases appropriately? +- [ ] Are there any logical errors? +- [ ] Is error handling implemented properly? + +### Code Quality + +- [ ] Does the code follow WordPress coding standards? +- [ ] Is the code well-organized and easy to understand? +- [ ] Are there any code smells (duplicate code, overly complex functions, etc.)? +- [ ] Are functions and variables named appropriately? +- [ ] Are there appropriate comments and documentation? + +### Security + +- [ ] Is user input properly validated and sanitized? +- [ ] Is output properly escaped? +- [ ] Are capability checks used for user actions? +- [ ] Are nonces used for form submissions? +- [ ] Are there any potential SQL injection vulnerabilities? +- [ ] Are there any potential XSS vulnerabilities? + +### Performance + +- [ ] Are there any performance bottlenecks? +- [ ] Are database queries optimized? +- [ ] Is caching used appropriately? +- [ ] Are assets (CSS, JS) properly enqueued? + +### Compatibility + +- [ ] Is the code compatible with the minimum supported WordPress version (5.0)? +- [ ] Is the code compatible with the minimum supported PHP version (7.0)? +- [ ] Are there any browser compatibility issues? +- [ ] Are there any conflicts with other plugins? + +### Internationalization + +- [ ] Are all user-facing strings translatable? +- [ ] Is the correct text domain used? +- [ ] Are translation functions used correctly? + +### Accessibility + +- [ ] Does the code follow accessibility best practices? +- [ ] Are ARIA attributes used appropriately? +- [ ] Is keyboard navigation supported? +- [ ] Is screen reader support implemented? + +## Code Review Process + +### 1. Understand the Context + +Before reviewing code, understand: +- What problem is the code trying to solve? +- What are the requirements? +- What are the constraints? + +### 2. Review the Code + +Review the code with the checklist above in mind. + +### 3. Provide Feedback + +When providing feedback: +- Be specific and clear +- Explain why a change is needed +- Provide examples or suggestions when possible +- Prioritize feedback (critical issues vs. minor improvements) +- Be constructive and respectful + +### 4. Follow Up + +After the code has been updated: +- Review the changes +- Verify that issues have been addressed +- Provide additional feedback if necessary + +## Common Issues to Look For + +### PHP Issues + +- Undefined variables or functions +- Incorrect function parameters +- Missing return statements +- Improper error handling +- Inefficient loops or conditionals +- Hardcoded values that should be configurable + +### WordPress-Specific Issues + +- Incorrect hook usage +- Missing or incorrect nonces +- Missing capability checks +- Direct database queries instead of using WordPress functions +- Improper enqueuing of scripts and styles +- Not using WordPress functions for common tasks + +### JavaScript Issues + +- Undefined variables or functions +- Event listener memory leaks +- jQuery conflicts +- Browser compatibility issues +- Missing error handling + +### CSS Issues + +- Browser compatibility issues +- Specificity issues +- Unused styles +- Overriding WordPress admin styles inappropriately + +## Example Feedback + +### Good Feedback Example + +``` +In function `handle_remove_reference()`: + +1. The nonce check is missing, which could lead to CSRF vulnerabilities. + Consider adding: + ```php + if (!isset($_GET['_wpnonce']) || !wp_verify_nonce($_GET['_wpnonce'], 'fpden_remove_reference')) { + wp_die(__('Security check failed.', 'fix-plugin-does-not-exist-notices')); + } + ``` + +2. The user capability check should be more specific. Instead of: + ```php + if (!current_user_can('manage_options')) { + ``` + Consider using: + ```php + if (!current_user_can('activate_plugins')) { + ``` + This is more appropriate for the action being performed. + +3. The success message should be translatable: + ```php + // Change this: + add_settings_error('fpden', 'fpden_removed', 'Plugin reference removed successfully.', 'updated'); + + // To this: + add_settings_error('fpden', 'fpden_removed', __('Plugin reference removed successfully.', 'fix-plugin-does-not-exist-notices'), 'updated'); + ``` +``` + +### Poor Feedback Example + +``` +This code has security issues and doesn't follow best practices. Fix it. +``` diff --git a/.github/ai-workflows/feature-development.md b/.github/ai-workflows/feature-development.md new file mode 100644 index 0000000..8c7dc2a --- /dev/null +++ b/.github/ai-workflows/feature-development.md @@ -0,0 +1,130 @@ +# Feature Development Guide for AI Assistants + +This document provides guidance for AI assistants to help with feature development for the Fix Plugin Does Not Exist Notices plugin. + +## Feature Development Workflow + +### 1. Create a Feature Branch + +Always start by creating a feature branch from the main branch: + +```bash +git checkout main +git pull github main +git checkout -b feature/descriptive-name +``` + +Use a descriptive name that clearly indicates what the feature is about. + +### 2. Implement the Feature + +When implementing a new feature: + +- Follow WordPress coding standards +- Ensure all strings are translatable +- Add appropriate comments +- Consider performance implications +- Maintain backward compatibility + +### 3. Update Documentation + +Update relevant documentation to reflect the new feature: + +- Add a description to CHANGELOG.md under an "Unreleased" section +- Update readme.txt if the feature affects user-facing functionality +- Update inline documentation/comments + +### 4. Testing + +Test the feature thoroughly: + +- Test with the latest WordPress version +- Test with the minimum supported WordPress version (5.0) +- Test with PHP 7.0+ (minimum supported version) +- Test in different environments (if possible) + +### 5. Commit Changes + +Make atomic commits with clear messages: + +```bash +git add . +git commit -m "Add feature: descriptive name" +``` + +### 6. Push to Remote + +Push the feature branch to the remote repositories: + +```bash +git push github HEAD:feature/descriptive-name +git push gitea HEAD:feature/descriptive-name +``` + +### 7. Create Pull Request (Optional) + +If the repository uses pull requests for code review, create a pull request from the feature branch to the main branch. + +## Code Standards and Best Practices + +### PHP Coding Standards + +- Follow [WordPress PHP Coding Standards](https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/) +- Use tabs for indentation, not spaces +- Use proper naming conventions: + - Class names: `Class_Name` + - Function names: `function_name` + - Variable names: `$variable_name` + +### JavaScript Coding Standards + +- Follow [WordPress JavaScript Coding Standards](https://developer.wordpress.org/coding-standards/wordpress-coding-standards/javascript/) +- Use tabs for indentation, not spaces +- Use proper naming conventions: + - Function names: `functionName` + - Variable names: `variableName` + +### Internationalization (i18n) + +- Wrap all user-facing strings in appropriate translation functions: + - `__()` for simple strings + - `_e()` for echoed strings + - `esc_html__()` for escaped strings + - `esc_html_e()` for escaped and echoed strings +- Always use the plugin's text domain: `fix-plugin-does-not-exist-notices` + +### Security Best Practices + +- Validate and sanitize all input +- Escape all output +- Use nonces for form submissions +- Use capability checks for user actions + +## Feature Types and Implementation Guidelines + +### Admin Interface Features + +When adding features to the admin interface: + +- Use WordPress admin UI components for consistency +- Follow WordPress admin UI patterns +- Ensure accessibility compliance +- Add appropriate help text + +### Plugin Functionality Features + +When adding core functionality: + +- Ensure compatibility with WordPress hooks system +- Consider performance impact +- Maintain backward compatibility +- Add appropriate error handling + +### Integration Features + +When adding integration with other plugins or services: + +- Make integrations optional when possible +- Check if the integrated plugin/service is available before using it +- Provide fallback functionality when the integration is not available +- Document the integration requirements diff --git a/.github/ai-workflows/release-process.md b/.github/ai-workflows/release-process.md new file mode 100644 index 0000000..b91264c --- /dev/null +++ b/.github/ai-workflows/release-process.md @@ -0,0 +1,173 @@ +# Release Process for AI Assistants + +This document provides step-by-step instructions for AI assistants to help with the release process for the Fix Plugin Does Not Exist Notices plugin. + +## Pre-Release Checklist + +- [ ] All features for this release are complete +- [ ] All bug fixes for this release are complete +- [ ] CHANGELOG.md is up to date +- [ ] readme.txt is up to date +- [ ] All tests pass + +## Determining the New Version Number + +Based on the changes made, determine the appropriate version increment: + +1. **PATCH** (e.g., 1.6.0 → 1.6.1): For bug fixes and minor improvements +2. **MINOR** (e.g., 1.6.0 → 1.7.0): For new features and significant improvements +3. **MAJOR** (e.g., 1.6.0 → 2.0.0): For breaking changes + +## Release Steps + +### 1. Create a New Branch + +```bash +git checkout -b v{MAJOR}.{MINOR}.{PATCH} +``` + +Example: +```bash +git checkout -b v1.7.0 +``` + +### 2. Update Version Numbers + +Update the version number in the following files: + +#### a. Main Plugin File (fix-plugin-does-not-exist-notices.php) + +```php +/** + * Plugin Name: Fix 'Plugin file does not exist.' Notices + * Plugin URI: https://wordpress.org/plugins/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: {MAJOR}.{MINOR}.{PATCH} + * ... + */ +``` + +Also update the FPDEN_VERSION constant: + +```php +define( 'FPDEN_VERSION', '{MAJOR}.{MINOR}.{PATCH}' ); +``` + +#### b. CHANGELOG.md + +Add a new section at the top of the CHANGELOG.md file: + +```markdown +## [{MAJOR}.{MINOR}.{PATCH}] - YYYY-MM-DD +### Added +- New feature 1 +- New feature 2 + +### Changed +- Change 1 +- Change 2 + +### Fixed +- Bug fix 1 +- Bug fix 2 +``` + +#### c. readme.txt + +Update the stable tag: + +``` +Stable tag: {MAJOR}.{MINOR}.{PATCH} +``` + +Add a new entry to the changelog section: + +``` += {MAJOR}.{MINOR}.{PATCH} = +* New feature 1 +* New feature 2 +* Change 1 +* Change 2 +* Fixed bug 1 +* Fixed bug 2 +``` + +Update the upgrade notice section: + +``` += {MAJOR}.{MINOR}.{PATCH} = +Brief description of the most important changes in this release +``` + +### 3. Commit Changes + +```bash +git add fix-plugin-does-not-exist-notices.php CHANGELOG.md readme.txt +git commit -m "Prepare release v{MAJOR}.{MINOR}.{PATCH}" +``` + +### 4. Push Branch to Remotes + +```bash +git push github HEAD:v{MAJOR}.{MINOR}.{PATCH} +git push gitea HEAD:v{MAJOR}.{MINOR}.{PATCH} +``` + +### 5. Create and Push Tag + +```bash +git tag -a v{MAJOR}.{MINOR}.{PATCH} -m "Release version {MAJOR}.{MINOR}.{PATCH}" +git push github refs/tags/v{MAJOR}.{MINOR}.{PATCH} +git push gitea refs/tags/v{MAJOR}.{MINOR}.{PATCH} +``` + +### 6. Monitor GitHub Actions + +Open the GitHub Actions page to monitor the build and deployment process: +https://github.com/wpallstars/fix-plugin-does-not-exist-notices/actions + +### 7. Verify Release + +- [ ] Check that the GitHub release was created successfully +- [ ] Verify that the plugin was deployed to WordPress.org +- [ ] Test the plugin from WordPress.org to ensure it works correctly + +## Rollback Procedure (If Needed) + +If issues are discovered after release: + +### 1. Create a Hotfix Branch + +```bash +git checkout v{MAJOR}.{MINOR}.{PATCH} +git checkout -b hotfix/v{MAJOR}.{MINOR}.{PATCH+1} +``` + +### 2. Fix the Issues + +Make the necessary changes to fix the issues. + +### 3. Update Version Numbers + +Increment the PATCH version and update all version numbers as described above. + +### 4. Commit and Push + +```bash +git add . +git commit -m "Fix issues in v{MAJOR}.{MINOR}.{PATCH}" +git push github HEAD:hotfix/v{MAJOR}.{MINOR}.{PATCH+1} +git push gitea HEAD:hotfix/v{MAJOR}.{MINOR}.{PATCH+1} +``` + +### 5. Create and Push Tag + +```bash +git tag -a v{MAJOR}.{MINOR}.{PATCH+1} -m "Hotfix release version {MAJOR}.{MINOR}.{PATCH+1}" +git push github refs/tags/v{MAJOR}.{MINOR}.{PATCH+1} +git push gitea refs/tags/v{MAJOR}.{MINOR}.{PATCH+1} +``` + +### 6. Monitor and Verify + +Follow steps 6 and 7 from the release process to monitor and verify the hotfix release. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fb813f1..baad02e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,6 +28,7 @@ jobs: cp readme.txt build/fix-plugin-does-not-exist-notices/ cp LICENSE build/fix-plugin-does-not-exist-notices/ cp README.md build/fix-plugin-does-not-exist-notices/ + cp -r assets build/fix-plugin-does-not-exist-notices/ - name: Create ZIP file run: | @@ -65,4 +66,4 @@ jobs: env: SVN_USERNAME: ${{ secrets.SVN_USERNAME }} SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} - SLUG: fix-plugin-does-not-exist-notices \ No newline at end of file + SLUG: fix-plugin-does-not-exist-notices diff --git a/.gitignore b/.gitignore index d95bd35..1d64fdb 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,10 @@ bower_components/ composer.lock package-lock.json +# Composer +vendor/ +composer.phar + # Build files build/ dist/ @@ -76,4 +80,4 @@ codecov.yml webpack.config.js gulpfile.js Gruntfile.js -*.zip \ No newline at end of file +*.zip \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 72064f1..6e86239 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,60 @@ All notable changes to this project will be documented in this file. +## [1.6.4] - 2024-05-16 +### Improved +- Version management to ensure consistent patch version increments +- Documentation for version update process +- AI workflow files with detailed version increment instructions + +## [1.6.3] - 2024-05-15 +### Fixed +- Git Updater repository URLs to use full repository paths +- Update URI configuration for proper update detection +- Version management following semantic versioning + +### Changed +- Updated organization name from 'WP All Stars' to 'WP ALLSTARS' +- Updated namespace from 'WPAllStars' to 'WPALLSTARS' + +## [1.6.2] - 2024-05-15 +### Changed +- Updated POT file version for consistency +- Improved JavaScript localization with proper fallbacks +- Enhanced code quality for WordPress.org submission +### Added +- Git Updater configuration with Update URI +- Update server URL configuration + +## [1.6.1] - 2024-05-15 +### Added +- AI assistant guide and workflow documentation +- Detailed release process documentation +- Feature development guidelines +- Bug fixing procedures +- Code review standards + +## [1.6.0] - 2024-05-15 +### Added +- Full translation support with POT file +- JavaScript localization for better multilingual support +- Plugin constants for improved code organization +- Git Updater support for updates from GitHub and Gitea + +### Changed +- Updated code to follow WordPress internationalization best practices +- Improved asset loading with version constants +- Smart update detection based on installation source + +## [1.5.0] - 2024-05-15 +### Added +- Improved compatibility with WordPress 6.4 +- Enhanced error detection for plugin references + +### Fixed +- Minor UI improvements for better visibility +- Accessibility enhancements for screen readers + ## [1.4.1] - 2023-11-30 ### Added - FAQ about keeping the plugin installed after notices are cleared @@ -104,4 +158,4 @@ All notable changes to this project will be documented in this file. ### Added - Initial release - "Remove Reference" button for plugin deactivation error notices -- AJAX processing for reference removal \ No newline at end of file +- AJAX processing for reference removal \ No newline at end of file diff --git a/README.md b/README.md index 8c08bb7..67fd9dc 100644 --- a/README.md +++ b/README.md @@ -120,35 +120,46 @@ The plugin works by: ## Changelog -### 1.4.1 -- Added FAQ about keeping the plugin installed after notices are cleared +### 1.6.4 +* Updated version management to ensure consistent patch version increments +* Improved documentation for version update process +* Enhanced AI workflow files with detailed version increment instructions -### 1.4.0 -- Updated plugin name and text domain -- Repository rename from plugin-reference-cleaner to fix-plugin-does-not-exist-notices +### 1.6.3 +* Fixed Git Updater repository URLs to use full repository paths +* Corrected Update URI configuration for proper update detection +* Improved version management following semantic versioning +* Updated organization name from 'WP All Stars' to 'WP ALLSTARS' +* Updated namespace from 'WPAllStars' to 'WPALLSTARS' -### 1.3.3 -* Improved notification placement next to WordPress error messages -* Added "Click here to scroll" button that automatically locates missing plugins -* Enhanced reliability with multiple injection methods -* Added visual arrow pointing from notification to error message +### 1.6.2 +* Updated POT file version for consistency +* Improved JavaScript localization with proper fallbacks +* Enhanced code quality for WordPress.org submission +* Added Git Updater configuration with Update URI +* Added update server URL configuration -### 1.3.2 -* Added prominent notification directly below WordPress error messages -* Improved user guidance with visual cues to connect error and solution -* Added eye-catching styling to help users understand how to fix errors +### 1.6.1 +* Added AI assistant guide and workflow documentation +* Added detailed release process documentation +* Added feature development guidelines +* Added bug fixing procedures +* Added code review standards -### 1.3.1 -* Added instructional notification explaining how to use the plugin -* Improved user guidance with step-by-step instructions -* Enhanced visual identification of missing plugins +### 1.6.0 +* Added full translation support with POT file +* Added JavaScript localization for better multilingual support +* Added plugin constants for improved code organization +* Added Git Updater support for updates from GitHub and Gitea +* Updated code to follow WordPress internationalization best practices +* Improved asset loading with version constants +* Added smart update detection based on installation source -### 1.3.0 -* Complete redesign for maximum compatibility with all WordPress themes -* Now adds missing plugins directly to the plugins list table -* Uses standard WordPress admin UI patterns instead of DOM manipulation -* Added "Remove Reference" action link in the plugins list -* Significantly improved reliability across all WordPress configurations +### 1.5.0 +* Improved compatibility with WordPress 6.4 +* Enhanced error detection for plugin references +* Minor UI improvements for better visibility +* Accessibility enhancements for screen readers [View full changelog](CHANGELOG.md) @@ -158,4 +169,4 @@ This project is licensed under the GPL-2.0+ License - see the [LICENSE](LICENSE) ## Support -For support, please visit [WP All Stars](https://www.wpallstars.com). \ No newline at end of file +For support, please visit [WP ALLSTARS](https://www.wpallstars.com). \ No newline at end of file diff --git a/assets/css/admin-styles.css b/assets/css/admin-styles.css new file mode 100644 index 0000000..c889c41 --- /dev/null +++ b/assets/css/admin-styles.css @@ -0,0 +1,28 @@ +.prc-notice { + border-left: 4px solid #ffba00; + background-color: #fff8e5; + padding: 10px 12px; + margin: 5px 0 15px; + font-size: 14px; + position: relative; +} +.prc-notice h3 { + margin-top: 0; + color: #826200; +} +.prc-notice::before { + content: ""; + position: absolute; + top: -10px; + left: 20px; + width: 0; + height: 0; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-bottom: 10px solid #fff8e5; +} + +/* Style for highlighting the missing plugin row */ +tr.inactive.prc-highlight-missing { + background-color: #fff8e5 !important; /* Use !important to override default styles */ +} diff --git a/assets/js/admin-scripts.js b/assets/js/admin-scripts.js new file mode 100644 index 0000000..55b8e71 --- /dev/null +++ b/assets/js/admin-scripts.js @@ -0,0 +1,88 @@ +(function() { + // Function to inject our notice + function injectNotice() { + // Find all notification containers first + var noticeContainers = document.querySelectorAll('.notice, .error, .updated'); + + // Find all error notifications about missing plugins + noticeContainers.forEach(function(notice) { + if (notice.textContent.includes('Plugin file does not exist') || + notice.textContent.includes('has been deactivated due to an error')) { + + // Check if we already added our notice + if (notice.nextElementSibling && notice.nextElementSibling.classList.contains('prc-notice')) { + return; + } + + // Create our custom notice + var ourNotice = document.createElement('div'); + ourNotice.className = 'prc-notice'; + + // Add content using localized strings passed via wp_localize_script + var pluginMissingText = typeof fpdenData !== 'undefined' && fpdenData.i18n && fpdenData.i18n.pluginMissing ? + fpdenData.i18n.pluginMissing : 'Plugin file missing'; + var removeReferenceText = typeof fpdenData !== 'undefined' && fpdenData.i18n && fpdenData.i18n.removeReference ? + fpdenData.i18n.removeReference : 'Remove Reference'; + var clickToScrollText = typeof fpdenData !== 'undefined' && fpdenData.i18n && fpdenData.i18n.clickToScroll ? + fpdenData.i18n.clickToScroll : 'Click here to scroll to missing plugins'; + + ourNotice.innerHTML = '
To remove the above error notification, scroll down to find the plugin marked with "(' + pluginMissingText + ')" and click its "' + removeReferenceText + '" link.
' + + 'This will permanently remove the missing plugin reference from your database.
' + + ''; + + // Insert our notice right after the error + notice.parentNode.insertBefore(ourNotice, notice.nextSibling); + + // Add scroll behavior + var scrollLink = document.getElementById('prc-scroll-to-plugin'); + if (scrollLink) { + scrollLink.addEventListener('click', function(e) { + e.preventDefault(); + var missingPlugins = document.querySelectorAll('tr.inactive:not(.plugin-update-tr)'); + for (var i = 0; i < missingPlugins.length; i++) { + if (missingPlugins[i].textContent.includes('(File Missing)')) { + // Add a class for highlighting instead of direct style manipulation + missingPlugins[i].classList.add('prc-highlight-missing'); + missingPlugins[i].scrollIntoView({ behavior: 'smooth', block: 'center' }); + // Optional: Remove highlight after a delay + setTimeout(function() { + missingPlugins[i].classList.remove('prc-highlight-missing'); + }, 3000); // Remove highlight after 3 seconds + return; + } + } + }); + } + } + }); + } + + // Try to inject notices on multiple events to ensure it works + document.addEventListener('DOMContentLoaded', function() { + injectNotice(); + + // Also set up a MutationObserver to watch for dynamically added notices + var observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + if (mutation.addedNodes && mutation.addedNodes.length > 0) { + // Check if added nodes are notices or contain notices + mutation.addedNodes.forEach(function(node) { + if (node.nodeType === 1 && (node.matches('.notice, .error, .updated') || node.querySelector('.notice, .error, .updated'))) { + injectNotice(); + } + }); + } + }); + }); + + // Start observing the body for changes in children + observer.observe(document.body, { childList: true, subtree: true }); + }); + + // Backup attempt with window.onload (less reliable than DOMContentLoaded but good fallback) + window.addEventListener('load', function() { + setTimeout(injectNotice, 500); // Delay slightly to ensure dynamic content is loaded + }); + +})(); diff --git a/build.sh b/build.sh index 3f21f78..34fd1b0 100755 --- a/build.sh +++ b/build.sh @@ -18,6 +18,10 @@ ZIP_FILE="${PLUGIN_SLUG}-${VERSION}.zip" echo "Creating build directory..." mkdir -p $BUILD_DIR +# Install composer dependencies +echo "Installing composer dependencies..." +composer install --no-dev --optimize-autoloader + # Copy required files echo "Copying plugin files..." cp fix-plugin-does-not-exist-notices.php $BUILD_DIR/ @@ -25,6 +29,18 @@ cp readme.txt $BUILD_DIR/ cp LICENSE $BUILD_DIR/ cp README.md $BUILD_DIR/ cp CHANGELOG.md $BUILD_DIR/ +cp composer.json $BUILD_DIR/ + +# Copy directories +echo "Copying directories..." +mkdir -p $BUILD_DIR/includes +cp -r includes/* $BUILD_DIR/includes/ +mkdir -p $BUILD_DIR/languages +cp -r languages/* $BUILD_DIR/languages/ +mkdir -p $BUILD_DIR/assets +cp -r assets/* $BUILD_DIR/assets/ +mkdir -p $BUILD_DIR/vendor +cp -r vendor/* $BUILD_DIR/vendor/ # Create ZIP file echo "Creating ZIP file..." @@ -39,4 +55,4 @@ if [ -f "$ZIP_FILE" ]; then else echo "❌ Build failed: ZIP file was not created" exit 1 -fi \ No newline at end of file +fi \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..a37e57f --- /dev/null +++ b/composer.json @@ -0,0 +1,21 @@ +{ + "name": "wpallstars/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.", + "type": "wordpress-plugin", + "license": "GPL-2.0-or-later", + "authors": [ + { + "name": "Marcus Quinn", + "email": "6428977+marcusquinn@users.noreply.github.com" + } + ], + "require": { + "php": ">=7.0", + "afragen/git-updater-lite": "^1" + }, + "autoload": { + "psr-4": { + "WPAllStars\\FixPluginDoesNotExistNotices\\": "includes/" + } + } +} diff --git a/fix-plugin-does-not-exist-notices.php b/fix-plugin-does-not-exist-notices.php index 3f55a49..957be8f 100644 --- a/fix-plugin-does-not-exist-notices.php +++ b/fix-plugin-does-not-exist-notices.php @@ -4,13 +4,16 @@ * * @package FixPluginDoesNotExistNotices * @author Marcus Quinn - * @copyright 2023 WP All Stars + * @copyright 2023 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/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: 1.4.2 + * Version: 1.6.4 * Author: Marcus Quinn * Author URI: https://www.wpallstars.com * License: GPL-2.0+ @@ -19,6 +22,11 @@ * Domain Path: /languages * Requires at least: 5.0 * Requires PHP: 7.0 + * Update URI: https://git-updater.wpallstars.com + * GitHub Plugin URI: wpallstars/fix-plugin-does-not-exist-notices + * GitHub Branch: main + * Gitea Plugin URI: wpallstars/fix-plugin-does-not-exist-notices + * Gitea Branch: main * * This plugin is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,310 +42,376 @@ * along with this plugin. If not, see https://www.gnu.org/licenses/gpl-2.0.html. */ -// Exit if accessed directly -if (!defined('ABSPATH')) { +// Exit if accessed directly. +if ( ! defined( 'ABSPATH' ) ) { exit; } -class Fix_Plugin_Does_Not_Exist_Notices { - public function __construct() { - // Add our plugin to the plugins list - add_filter('all_plugins', array($this, 'add_missing_plugins_references')); - - // Add our action link to the plugins list - add_filter('plugin_action_links', array($this, 'add_remove_reference_action'), 20, 4); - - // Handle the remove reference action - add_action('admin_init', array($this, 'handle_remove_reference')); - - // Add admin notices for operation feedback - add_action('admin_notices', array($this, 'admin_notices')); - } - - /** - * Find and add invalid plugin references to the plugins list - */ - public function add_missing_plugins_references($plugins) { - // Only run on the plugins page - if (!$this->is_plugins_page()) { - return $plugins; - } +// Define plugin constants +define( 'FPDEN_VERSION', '1.6.4' ); +define( 'FPDEN_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); +define( 'FPDEN_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); +define( 'FPDEN_PLUGIN_FILE', __FILE__ ); +define( 'FPDEN_PLUGIN_BASENAME', plugin_basename( __FILE__ ) ); - // Get active plugins that don't exist - $invalid_plugins = $this->get_invalid_plugins(); - - // Add each invalid plugin to the plugin list - foreach ($invalid_plugins as $plugin_path) { - if (!isset($plugins[$plugin_path])) { - $plugin_name = basename($plugin_path); - $plugins[$plugin_path] = array( - 'Name' => $plugin_name . ' (File Missing)', - 'Description' => 'This plugin is still marked as "Active" in your database — but its folder and files can\'t be found in /wp-content/plugins/. Click "Remove Reference" to permanently remove it from your active plugins list and eliminate the error notice.', - 'Version' => 'N/A', - 'Author' => '', - 'PluginURI' => '', - 'AuthorURI' => '', - 'Title' => $plugin_name . ' (Missing)', - 'AuthorName' => '' - ); - } - } - - return $plugins; - } - - /** - * Add the Remove Reference action link to invalid plugins - */ - public function add_remove_reference_action($actions, $plugin_file, $plugin_data, $context) { - // Only run on the plugins page - if (!$this->is_plugins_page()) { - return $actions; - } - - // Check if this is a missing plugin - if (isset($plugin_data['Name']) && strpos($plugin_data['Name'], '(File Missing)') !== false) { - // Clear existing actions - $actions = array(); - - // Add our action - $nonce = wp_create_nonce('remove_plugin_reference_' . $plugin_file); - $remove_url = admin_url('plugins.php?action=remove_reference&plugin=' . urlencode($plugin_file) . '&_wpnonce=' . $nonce); - $actions['remove_reference'] = 'Remove Reference'; - } - - return $actions; - } - - /** - * Handle the remove reference action - */ - public function handle_remove_reference() { - // Check if we're removing a reference - if (!isset($_GET['action']) || $_GET['action'] !== 'remove_reference' || !isset($_GET['plugin'])) { - return; - } - - // Verify permissions - if (!current_user_can('activate_plugins')) { - wp_die(__('You do not have sufficient permissions to perform this action.', 'fix-plugin-does-not-exist-notices')); - } - - // Get the plugin file - $plugin_file = isset($_GET['plugin']) ? $_GET['plugin'] : ''; - - // Verify nonce - check_admin_referer('remove_plugin_reference_' . $plugin_file); - - // Remove the plugin reference - $success = $this->remove_plugin_reference($plugin_file); - - // Redirect back to plugins page with a message - $redirect = admin_url('plugins.php'); - $redirect = add_query_arg($success ? 'reference_removed' : 'reference_removal_failed', '1', $redirect); - wp_redirect($redirect); - exit; - } - - /** - * Remove a plugin reference from the active plugins - */ - public function remove_plugin_reference($plugin_file) { - $success = false; - - // Handle multisite network admin - if (is_multisite() && is_network_admin()) { - $active_plugins = get_site_option('active_sitewide_plugins', array()); - if (isset($active_plugins[$plugin_file])) { - unset($active_plugins[$plugin_file]); - $success = update_site_option('active_sitewide_plugins', $active_plugins); - } - } - // Handle single site or multisite subsite - else { - $active_plugins = get_option('active_plugins', array()); - $key = array_search($plugin_file, $active_plugins); - if ($key !== false) { - unset($active_plugins[$key]); - $active_plugins = array_values($active_plugins); // Re-index array - $success = update_option('active_plugins', $active_plugins); - } - } - - return $success; - } - - /** - * Display admin notices - */ - public function admin_notices() { - // Only run on the plugins page - if (!$this->is_plugins_page()) { - return; - } - - // Get invalid plugins - $invalid_plugins = $this->get_invalid_plugins(); - - // Create a highlighted notice immediately after WordPress error messages - if (!empty($invalid_plugins)) { - // Add a notice specifically targeting the WordPress error notification - // Use admin_head to ensure it runs early in the page load process - add_action('admin_head', function() use ($invalid_plugins) { - ?> - - - '; - echo 'Missing plugin files detected: The plugins listed below with (File Missing) tag no longer exist but are still referenced in your database.
'; - echo 'How to fix: Click the "Remove Reference" link next to each missing plugin to safely remove it from your active plugins list.
'; - echo 'This will clean up your database and remove the error notifications.
'; - echo ''; - } - - // Show success message - if (isset($_GET['reference_removed']) && $_GET['reference_removed'] === '1') { - echo 'Plugin reference removed successfully.
Failed to remove plugin reference. The plugin may already have been removed.
/wp-content/plugins/
'
+ ),
+ 'Version' => __( 'N/A', 'fix-plugin-does-not-exist-notices' ),
+ 'Author' => '',
+ 'PluginURI' => '',
+ 'AuthorURI' => '',
+ 'Title' => $plugin_name . ' (' . __( 'Missing', 'fix-plugin-does-not-exist-notices' ) . ')',
+ 'AuthorName' => '',
+ );
+ }
+ }
+
+ return $plugins;
+ }
+
+ /**
+ * Add the Remove Reference action link to invalid plugins.
+ *
+ * Filters the action links displayed for each plugin on the plugins page.
+ * Adds a "Remove Reference" link for plugins identified as missing.
+ *
+ * @param array $actions An array of plugin action links.
+ * @param string $plugin_file Path to the plugin file relative to the plugins directory.
+ * @param array $plugin_data An array of plugin data.
+ * @param string $context The plugin context (e.g., 'all', 'active', 'inactive').
+ * @return array The potentially modified array of plugin action links.
+ * @noinspection PhpUnusedParameterInspection
+ */
+ public function add_remove_reference_action( $actions, $plugin_file, $plugin_data, $context ) {
+ // Only run on the plugins page.
+ if ( ! $this->is_plugins_page() ) {
+ return $actions;
+ }
+
+ // Check if this is a missing plugin identified by our previous filter.
+ if ( isset( $plugin_data['Name'] ) && strpos( $plugin_data['Name'], '(File Missing)' ) !== false ) {
+ // Clear existing actions like "Activate", "Deactivate", "Edit".
+ $actions = array();
+
+ // Add our custom action.
+ $nonce = wp_create_nonce( 'remove_plugin_reference_' . $plugin_file );
+ $remove_url = admin_url( 'plugins.php?action=remove_reference&plugin=' . urlencode( $plugin_file ) . '&_wpnonce=' . $nonce );
+ /* translators: %s: Plugin file path */
+ $aria_label = sprintf( __( 'Remove reference to missing plugin %s', 'fix-plugin-does-not-exist-notices' ), esc_attr( $plugin_file ) );
+ $actions['remove_reference'] = '' . esc_html__( 'Remove Reference', 'fix-plugin-does-not-exist-notices' ) . '';
+ }
+
+ return $actions;
+ }
+
+ /**
+ * Handle the remove reference action triggered by the link.
+ *
+ * Checks for the correct action, verifies nonce and permissions,
+ * calls the removal function, and redirects back to the plugins page.
+ *
+ * @return void
+ */
+ public function handle_remove_reference() {
+ // Check if our specific action is being performed.
+ if ( ! isset( $_GET['action'] ) || 'remove_reference' !== $_GET['action'] || ! isset( $_GET['plugin'] ) ) {
+ return;
+ }
+
+ // Verify user permissions.
+ if ( ! current_user_can( 'activate_plugins' ) ) {
+ wp_die( esc_html__( 'You do not have sufficient permissions to perform this action.', 'fix-plugin-does-not-exist-notices' ) );
+ }
+
+ // Sanitize and get the plugin file path.
+ $plugin_file = isset( $_GET['plugin'] ) ? sanitize_text_field( wp_unslash( $_GET['plugin'] ) ) : '';
+ if ( empty( $plugin_file ) ) {
+ wp_die( esc_html__( 'Invalid plugin specified.', 'fix-plugin-does-not-exist-notices' ) );
+ }
+
+ // Verify nonce for security.
+ check_admin_referer( 'remove_plugin_reference_' . $plugin_file );
+
+ // Attempt to remove the plugin reference.
+ $success = $this->remove_plugin_reference( $plugin_file );
+
+ // Prepare redirect URL with feedback query args.
+ $redirect_url = admin_url( 'plugins.php' );
+ $redirect_url = add_query_arg( $success ? 'reference_removed' : 'reference_removal_failed', '1', $redirect_url );
+
+ // Redirect and exit.
+ wp_safe_redirect( $redirect_url );
+ exit;
+ }
+
+ /**
+ * Remove a plugin reference from the active plugins list in the database.
+ *
+ * Handles both single site and multisite network activated plugins.
+ *
+ * @param string $plugin_file The plugin file path to remove.
+ * @return bool True on success, false on failure or if the plugin wasn't found.
+ */
+ public function remove_plugin_reference( $plugin_file ) {
+ $success = false;
+
+ // Ensure plugin file path is provided.
+ if ( empty( $plugin_file ) ) {
+ return false;
+ }
+
+ // Handle multisite network admin context.
+ if ( is_multisite() && is_network_admin() ) {
+ $active_plugins = get_site_option( 'active_sitewide_plugins', array() );
+ // Network active plugins are stored as key => timestamp.
+ if ( isset( $active_plugins[ $plugin_file ] ) ) {
+ unset( $active_plugins[ $plugin_file ] );
+ $success = update_site_option( 'active_sitewide_plugins', $active_plugins );
+ }
+ } else { // Handle single site or non-network admin context.
+ $active_plugins = get_option( 'active_plugins', array() );
+ // Single site active plugins are stored as an indexed array.
+ $key = array_search( $plugin_file, $active_plugins, true ); // Use strict comparison.
+ if ( false !== $key ) {
+ unset( $active_plugins[ $key ] );
+ // Re-index the array numerically.
+ $active_plugins = array_values( $active_plugins );
+ $success = update_option( 'active_plugins', $active_plugins );
+ }
+ }
+
+ return $success;
+ }
+
+ /**
+ * Display admin notices on the plugins page.
+ *
+ * Shows informational notices about missing plugins and feedback
+ * messages after attempting to remove a reference.
+ *
+ * @return void
+ */
+ public function admin_notices() {
+ // Only run on the plugins page.
+ if ( ! $this->is_plugins_page() ) {
+ return;
+ }
+
+ // Check for feedback messages from the remove action.
+ if ( isset( $_GET['reference_removed'] ) && '1' === $_GET['reference_removed'] ) {
+ ?>
+ + + + () + +
++ + +
+ +