-
Notifications
You must be signed in to change notification settings - Fork 146
Show plugin cards when external requests are disabled #2190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Changes from 11 commits
d1dae91
d40dca2
727be0c
d49280c
9db2772
2c2777f
661fa92
0e26be7
19f15f0
e79cc1c
e4e34af
2270f60
9598ba3
9ae95ab
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think these functions can be put directly into |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,225 @@ | ||||||||||||||||||||||||||||||||||||||||
| <?php | ||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||
| * Local Plugin Fallback functionality for Performance Lab. | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * Provides fallback functionality to show plugin cards for locally installed | ||||||||||||||||||||||||||||||||||||||||
| * performance-related plugins when external API requests are disabled or fail. | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @package performance-lab | ||||||||||||||||||||||||||||||||||||||||
| * @since n.e.x.t | ||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // @codeCoverageIgnoreStart | ||||||||||||||||||||||||||||||||||||||||
| if ( ! defined( 'ABSPATH' ) ) { | ||||||||||||||||||||||||||||||||||||||||
| exit; // Exit if accessed directly. | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| // @codeCoverageIgnoreEnd | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // Ensure this file is loaded when Performance Lab plugin is active. | ||||||||||||||||||||||||||||||||||||||||
| if ( ! function_exists( 'perflab_get_local_plugin_fallback_data' ) ) { | ||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These functions should not be "pluggable". You can remove the |
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||
| * Gets local plugin information for Performance Lab standalone plugins. | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * This function provides fallback data when external API requests to WordPress.org | ||||||||||||||||||||||||||||||||||||||||
| * are disabled or fail, allowing the Performance Lab interface to still show | ||||||||||||||||||||||||||||||||||||||||
| * cards for locally installed performance plugins. | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @since n.e.x.t | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @param string[] $plugin_slugs Array of plugin slugs to get local info for. | ||||||||||||||||||||||||||||||||||||||||
| * @return array<string, array{name: string, slug: string, short_description: string, requires: string|false, requires_php: string|false, requires_plugins: string[], version: string, is_installed: bool, is_active: bool}> Local plugin data keyed by slug. | ||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||
| function perflab_get_local_plugin_fallback_data( array $plugin_slugs ): array { | ||||||||||||||||||||||||||||||||||||||||
| // Ensure we have access to plugin functions. | ||||||||||||||||||||||||||||||||||||||||
| if ( ! function_exists( 'get_plugins' ) ) { | ||||||||||||||||||||||||||||||||||||||||
| require_once ABSPATH . 'wp-admin/includes/plugin.php'; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| $local_plugins = get_plugins(); | ||||||||||||||||||||||||||||||||||||||||
| $fallback_data = array(); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| foreach ( $plugin_slugs as $plugin_slug ) { | ||||||||||||||||||||||||||||||||||||||||
| // Look for plugin files that match this slug. | ||||||||||||||||||||||||||||||||||||||||
| $plugin_file = perflab_find_local_plugin_file( $local_plugins, $plugin_slug ); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if ( false === $plugin_file ) { | ||||||||||||||||||||||||||||||||||||||||
| continue; // Plugin not installed locally. | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| $plugin_headers = $local_plugins[ $plugin_file ]; | ||||||||||||||||||||||||||||||||||||||||
| $is_active = is_plugin_active( $plugin_file ); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // Build normalized plugin data similar to WordPress.org API response. | ||||||||||||||||||||||||||||||||||||||||
| $readme_description = perflab_get_plugin_readme_description( $plugin_file ); | ||||||||||||||||||||||||||||||||||||||||
| $description = '' !== $readme_description ? $readme_description : ( $plugin_headers['Description'] ?? '' ); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| $fallback_data[ $plugin_slug ] = array( | ||||||||||||||||||||||||||||||||||||||||
| 'name' => $plugin_headers['Name'] ?? $plugin_slug, | ||||||||||||||||||||||||||||||||||||||||
| 'slug' => $plugin_slug, | ||||||||||||||||||||||||||||||||||||||||
| 'short_description' => $description, | ||||||||||||||||||||||||||||||||||||||||
| 'requires' => $plugin_headers['RequiresWP'] ?? false, | ||||||||||||||||||||||||||||||||||||||||
| 'requires_php' => $plugin_headers['RequiresPHP'] ?? false, | ||||||||||||||||||||||||||||||||||||||||
| 'requires_plugins' => perflab_parse_requires_plugins( $plugin_headers, $plugin_slug ), | ||||||||||||||||||||||||||||||||||||||||
| 'version' => $plugin_headers['Version'] ?? '0.0.0', | ||||||||||||||||||||||||||||||||||||||||
| 'is_installed' => true, | ||||||||||||||||||||||||||||||||||||||||
| 'is_active' => $is_active, | ||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| return $fallback_data; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||
| * Finds the plugin file for a given slug among installed plugins. | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @since n.e.x.t | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @param array<string, array<string, string>> $local_plugins Array from get_plugins(). | ||||||||||||||||||||||||||||||||||||||||
| * @param string $plugin_slug Plugin slug to find. | ||||||||||||||||||||||||||||||||||||||||
| * @return string|false Plugin file path relative to plugins directory, or false if not found. | ||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||
| function perflab_find_local_plugin_file( array $local_plugins, string $plugin_slug ) { | ||||||||||||||||||||||||||||||||||||||||
| foreach ( $local_plugins as $plugin_file => $plugin_data ) { | ||||||||||||||||||||||||||||||||||||||||
| // Extract directory name from plugin file path. | ||||||||||||||||||||||||||||||||||||||||
| $plugin_dir = strtok( $plugin_file, '/' ); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if ( $plugin_dir === $plugin_slug ) { | ||||||||||||||||||||||||||||||||||||||||
| return $plugin_file; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||
| * Gets plugin description from readme file. | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @since n.e.x.t | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @param string $plugin_file Plugin file path. | ||||||||||||||||||||||||||||||||||||||||
| * @return string Plugin description from readme or empty string. | ||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||
| function perflab_get_plugin_readme_description( string $plugin_file ): string { | ||||||||||||||||||||||||||||||||||||||||
| if ( ! defined( 'WP_PLUGIN_DIR' ) ) { | ||||||||||||||||||||||||||||||||||||||||
| return ''; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This constant is always defined. No need for this
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
| $plugin_dir = dirname( WP_PLUGIN_DIR . '/' . $plugin_file ); | ||||||||||||||||||||||||||||||||||||||||
| $readme_files = array( 'readme.txt', 'README.txt', 'readme.md', 'README.md' ); | ||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The plugins we feature all use |
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| foreach ( $readme_files as $readme_file ) { | ||||||||||||||||||||||||||||||||||||||||
| $readme_path = $plugin_dir . '/' . $readme_file; | ||||||||||||||||||||||||||||||||||||||||
| if ( file_exists( $readme_path ) ) { | ||||||||||||||||||||||||||||||||||||||||
| $readme_content = file_get_contents( $readme_path ); | ||||||||||||||||||||||||||||||||||||||||
| if ( false !== $readme_content ) { | ||||||||||||||||||||||||||||||||||||||||
| // Parse description from readme - look for description after "== Description ==". | ||||||||||||||||||||||||||||||||||||||||
| if ( 1 === preg_match( '/==\s*Description\s*==(.*?)(?==|\z)/is', $readme_content, $matches ) ) { | ||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this regular expression right? The description is the paragraph before the performance/plugins/performance-lab/readme.txt Lines 1 to 14 in 4f17dd7
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These two conditions can be combined. |
||||||||||||||||||||||||||||||||||||||||
| $description = trim( $matches[1] ); | ||||||||||||||||||||||||||||||||||||||||
| // Remove markdown formatting and clean up. | ||||||||||||||||||||||||||||||||||||||||
| $description = preg_replace( '/\*\*(.*?)\*\*/', '$1', $description ) ?? $description; | ||||||||||||||||||||||||||||||||||||||||
| $description = preg_replace( '/\*(.*?)\*/', '$1', $description ) ?? $description; | ||||||||||||||||||||||||||||||||||||||||
| $description = preg_replace( '/\[([^\]]+)\]\([^\)]+\)/', '$1', $description ) ?? $description; | ||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Markdown isn't allowed in plugin descriptions, so these can be removed.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
| return trim( $description ); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| return ''; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||
| * Sanitizes plugin description for display. | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @since n.e.x.t | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @param string $description Raw plugin description. | ||||||||||||||||||||||||||||||||||||||||
| * @return string Sanitized description. | ||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||
| function perflab_sanitize_plugin_description( string $description ): string { | ||||||||||||||||||||||||||||||||||||||||
| if ( '' === $description ) { | ||||||||||||||||||||||||||||||||||||||||
| return ''; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // Strip all HTML tags and decode entities. | ||||||||||||||||||||||||||||||||||||||||
| $description = wp_strip_all_tags( $description ); | ||||||||||||||||||||||||||||||||||||||||
| $description = html_entity_decode( $description, ENT_QUOTES, 'UTF-8' ); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| return trim( $description ); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function isn't used anymore.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||
| * Parses the requires_plugins from plugin headers. | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * This attempts to extract required plugins from various possible header formats. | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @since n.e.x.t | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @param array<string, string> $plugin_headers Plugin headers array. | ||||||||||||||||||||||||||||||||||||||||
| * @param string $plugin_slug Plugin slug to determine dependencies. | ||||||||||||||||||||||||||||||||||||||||
| * @return string[] Array of required plugin slugs. | ||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||
| function perflab_parse_requires_plugins( array $plugin_headers, string $plugin_slug ): array { | ||||||||||||||||||||||||||||||||||||||||
| $requires_plugins = array(); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // Check for RequiresPlugins header (WordPress 6.5+). | ||||||||||||||||||||||||||||||||||||||||
| if ( isset( $plugin_headers['RequiresPlugins'] ) && '' !== $plugin_headers['RequiresPlugins'] ) { | ||||||||||||||||||||||||||||||||||||||||
| $plugins = array_map( 'trim', explode( ',', $plugin_headers['RequiresPlugins'] ) ); | ||||||||||||||||||||||||||||||||||||||||
| $requires_plugins = array_merge( $requires_plugins, $plugins ); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // For known Performance Lab plugins, add their specific dependencies. | ||||||||||||||||||||||||||||||||||||||||
| // Embed Optimizer has a hard dependency on Optimization Detective. | ||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
| if ( 'embed-optimizer' === $plugin_slug ) { | ||||||||||||||||||||||||||||||||||||||||
| $requires_plugins[] = 'optimization-detective'; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This logic is now duplicated with: performance/plugins/performance-lab/includes/admin/plugins.php Lines 429 to 432 in 4f17dd7
It would be good to extract this into a separate helper function. In fact, this information could be added as part of |
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // Image Prioritizer has a hard dependency on Optimization Detective. | ||||||||||||||||||||||||||||||||||||||||
| if ( 'image-prioritizer' === $plugin_slug ) { | ||||||||||||||||||||||||||||||||||||||||
| $requires_plugins[] = 'optimization-detective'; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this needed? It would be parsed out of |
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| return array_unique( array_filter( $requires_plugins ) ); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||
| * Checks if external requests are blocked or likely to fail. | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @since n.e.x.t | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @return bool True if external requests are blocked or should be avoided. | ||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||
| function perflab_are_external_requests_blocked(): bool { | ||||||||||||||||||||||||||||||||||||||||
| // Check if external requests are explicitly blocked. | ||||||||||||||||||||||||||||||||||||||||
| if ( defined( 'WP_HTTP_BLOCK_EXTERNAL' ) && WP_HTTP_BLOCK_EXTERNAL ) { | ||||||||||||||||||||||||||||||||||||||||
| // Check if wordpress.org is in the allowed hosts. | ||||||||||||||||||||||||||||||||||||||||
| $allowed_hosts = defined( 'WP_ACCESSIBLE_HOSTS' ) ? WP_ACCESSIBLE_HOSTS : ''; | ||||||||||||||||||||||||||||||||||||||||
| if ( '' === $allowed_hosts ) { | ||||||||||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| $allowed_hosts_array = array_map( 'trim', explode( ',', $allowed_hosts ) ); | ||||||||||||||||||||||||||||||||||||||||
| if ( ! in_array( 'wordpress.org', $allowed_hosts_array, true ) ) { | ||||||||||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||
| * Gets plugin settings URL for a given plugin slug. | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * This attempts to determine the settings URL for locally installed performance plugins. | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @since n.e.x.t | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @param string $plugin_slug Plugin slug. | ||||||||||||||||||||||||||||||||||||||||
| * @return string|null Settings URL or null if not available. | ||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||
| function perflab_get_local_plugin_settings_url( string $plugin_slug ): ?string { | ||||||||||||||||||||||||||||||||||||||||
| return perflab_get_plugin_settings_url( $plugin_slug ); | ||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function is no longer used.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| } // Close the function_exists check. | ||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed? It's already being loaded below.