diff --git a/plugins/embed-optimizer/readme.txt b/plugins/embed-optimizer/readme.txt index 156c86f0ad..c8301910c1 100644 --- a/plugins/embed-optimizer/readme.txt +++ b/plugins/embed-optimizer/readme.txt @@ -5,7 +5,7 @@ Tested up to: 6.8 Stable tag: 1.0.0-beta2 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html -Tags: performance, embeds +Tags: performance, embeds, optimization-detective Optimizes the performance of embeds through lazy-loading, preconnecting, and reserving space to reduce layout shifts. diff --git a/plugins/image-prioritizer/readme.txt b/plugins/image-prioritizer/readme.txt index 4e58107351..a2c0658bf6 100644 --- a/plugins/image-prioritizer/readme.txt +++ b/plugins/image-prioritizer/readme.txt @@ -5,7 +5,7 @@ Tested up to: 6.8 Stable tag: 1.0.0-beta2 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html -Tags: performance, optimization, image, lcp, lazy-load +Tags: performance, optimization, image, lcp, lazy-load, optimization-detective Prioritizes the loading of images and videos based on how they appear to actual visitors: adds fetchpriority, preloads, lazy-loads, and sets sizes. diff --git a/plugins/optimization-detective/helper.php b/plugins/optimization-detective/helper.php index 75f985102a..0f8c4d637a 100644 --- a/plugins/optimization-detective/helper.php +++ b/plugins/optimization-detective/helper.php @@ -197,6 +197,135 @@ function od_render_generator_meta_tag(): void { echo '' . "\n"; } +/** + * Adds an Extensions link to the plugin action links for Optimization Detective. + * + * This link directs users to the plugin directory to discover extensions that + * provide optimization functionality using the Optimization Detective plugin. + * + * @since n.e.x.t + * @access private + * + * @param string[]|mixed $links List of plugin action links HTML. + * @return string[]|mixed Modified list of plugin action links HTML. + */ +function od_render_extensions_action_link( $links ) { + if ( ! is_array( $links ) ) { + return $links; + } + + $extensions_link = sprintf( + '%2$s', + esc_url( admin_url( 'plugin-install.php?s=optimization-detective&tab=search&type=tag' ) ), + esc_html__( 'Extensions', 'optimization-detective' ) + ); + + return array_merge( + array( 'extensions' => $extensions_link ), + $links + ); +} + +/** + * Checks for installed extensions of Optimization Detective. + * + * @since n.e.x.t + * @access private + * + * @return string[] List of installed extension plugin slugs. + */ +function od_check_installed_extensions(): array { + $installed_plugins = get_plugins(); + $installed_extensions = array(); + + foreach ( $installed_plugins as $plugin_slug => $plugin_data ) { + if ( isset( $plugin_data['RequiresPlugins'] ) && 'optimization-detective' === $plugin_data['RequiresPlugins'] ) { + $installed_extensions[] = $plugin_slug; + } + } + + // Check for plugins without Requires Plugins header but known to be extensions. + $extensions = array( + 'embed-optimizer/load.php', + ); + $installed_extensions = array_merge( $installed_extensions, array_intersect( $extensions, array_keys( $installed_plugins ) ) ); + + return $installed_extensions; +} + +/** + * Renders an admin notice prompting the user to install extensions for Optimization Detective. + * + * @since n.e.x.t + * @access private + */ +function od_maybe_render_installed_extensions_admin_notice(): void { + $message = sprintf( + '

%s

', + esc_html__( 'Optimization Detective does not provide any functionality on its own.', 'optimization-detective' ) + ); + + $message .= '

' . esc_html__( 'This plugin is a framework that requires extension plugins to provide optimization features. To benefit from Optimization Detective, please install one or more of the following extensions:', 'optimization-detective' ) . '

'; + + $extensions = array( + 'image-prioritizer' => array( + 'name' => __( 'Image Prioritizer', 'optimization-detective' ), + 'description' => __( 'Prioritizes the loading of images and videos based on how visible they are to actual visitors; adds fetchpriority and applies lazy-loading.', 'optimization-detective' ), + 'url' => admin_url( 'plugin-install.php?tab=plugin-information&plugin=image-prioritizer&TB_iframe=true&width=772' ), + ), + 'embed-optimizer' => array( + 'name' => __( 'Embed Optimizer', 'optimization-detective' ), + 'description' => __( 'Optimizes the performance of embeds through lazy-loading, preconnecting, and reserving space to reduce layout shifts.', 'optimization-detective' ), + 'url' => admin_url( 'plugin-install.php?tab=plugin-information&plugin=embed-optimizer&TB_iframe=true&width=772' ), + ), + ); + + $message .= ''; + foreach ( $extensions as $extension ) { + $message .= sprintf( + ' + + + ', + esc_url( $extension['url'] ), + esc_html( $extension['name'] ), + esc_html( $extension['description'] ) + ); + } + $message .= '
%s%s
'; + + $notice = wp_get_admin_notice( + $message, + array( + 'type' => 'warning', + 'paragraph_wrap' => false, + ) + ); + + add_thickbox(); + echo wp_kses( $notice, wp_kses_allowed_html( 'post' ) ); +} + +/** + * Checks for installed extensions and displays an admin notice once if none are found. + * + * @since n.e.x.t + * @access private + */ +function od_maybe_check_installed_extensions(): void { + if ( 1 === (int) get_option( 'od_installed_extensions_admin_notice', '0' ) ) { + return; + } + update_option( 'od_installed_extensions_admin_notice', '1' ); + + $installed_extensions = od_check_installed_extensions(); + if ( count( $installed_extensions ) > 0 ) { + return; + } + + add_action( 'admin_notices', 'od_maybe_render_installed_extensions_admin_notice' ); +} + /** * Gets the path to a script or stylesheet. * diff --git a/plugins/optimization-detective/hooks.php b/plugins/optimization-detective/hooks.php index 584e88e745..5af80f70ea 100644 --- a/plugins/optimization-detective/hooks.php +++ b/plugins/optimization-detective/hooks.php @@ -23,7 +23,9 @@ add_action( 'wp_head', 'od_render_generator_meta_tag' ); add_filter( 'site_status_tests', 'od_add_rest_api_availability_test' ); add_action( 'admin_init', 'od_maybe_run_rest_api_health_check' ); +add_action( 'load-plugins.php', 'od_maybe_check_installed_extensions' ); add_action( 'after_plugin_row_meta', 'od_render_rest_api_health_check_admin_notice_in_plugin_row', 30 ); +add_filter( 'plugin_action_links_optimization-detective/load.php', 'od_render_extensions_action_link' ); add_action( 'rest_api_init', 'od_register_rest_url_metric_store_endpoint' ); add_filter( 'rest_pre_dispatch', 'od_decompress_rest_request_body', 10, 3 ); add_action( 'od_trigger_page_cache_invalidation', 'od_trigger_post_update_actions' ); diff --git a/plugins/optimization-detective/uninstall.php b/plugins/optimization-detective/uninstall.php index 3400386724..e6dc084532 100644 --- a/plugins/optimization-detective/uninstall.php +++ b/plugins/optimization-detective/uninstall.php @@ -18,8 +18,9 @@ OD_URL_Metrics_Post_Type::delete_all_posts(); wp_unschedule_hook( OD_URL_Metrics_Post_Type::GC_CRON_EVENT_NAME ); - // Clear out site health check data. + // Clear out options and transients. delete_option( 'od_rest_api_unavailable' ); + delete_option( 'od_installed_extensions_admin_notice' ); delete_transient( 'od_rest_api_health_check_response' ); };