From 2892386b74f455fef225c0731f8b6fa7a6dfe699 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 9 Jan 2025 11:55:50 -0800 Subject: [PATCH] Flesh out inline phpdoc for od_init and od_register_tag_visitors actions --- plugins/optimization-detective/helper.php | 16 +++++ .../optimization-detective/optimization.php | 71 +++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/plugins/optimization-detective/helper.php b/plugins/optimization-detective/helper.php index 27073205d..2159e1874 100644 --- a/plugins/optimization-detective/helper.php +++ b/plugins/optimization-detective/helper.php @@ -19,6 +19,22 @@ function od_initialize_extensions(): void { /** * Fires when extensions to Optimization Detective can be loaded and initialized. * + * This action is useful for loading extension code that depends on Optimization Detective to be running. The version + * of the plugin is passed as the sole argument so that if the required version is not present, the callback can short circuit. + * + * Example: + * + * add_action( 'od_init', function ( string $version ) { + * if ( version_compare( $version, '1.0', '<' ) ) { + * add_action( 'admin_notices', 'my_plugin_warn_optimization_plugin_outdated' ); + * return; + * } + * + * // Bootstrap the Optimization Detective extension. + * require_once __DIR__ . '/functions.php'; + * // ... + * } ); + * * @since 0.7.0 * * @param string $version Optimization Detective version. diff --git a/plugins/optimization-detective/optimization.php b/plugins/optimization-detective/optimization.php index fa72a6194..de5c8c8d2 100644 --- a/plugins/optimization-detective/optimization.php +++ b/plugins/optimization-detective/optimization.php @@ -204,6 +204,77 @@ function od_optimize_template_output_buffer( string $buffer ): string { /** * Fires to register tag visitors before walking over the document to perform optimizations. * + * Once a page has finished rendering and the output buffer is processed, the page contents are loaded into + * an HTML Tag Processor instance. It then iterates over each tag in the document, and at each open tag it will + * invoke all registered tag visitors. A tag visitor is simply a callable (such as a regular function, closure, + * or even a class with an `__invoke` method defined). The tag visitor callback is invoked by passing an instance + * of the `OD_Tag_Visitor_Context` object which includes the following read-only properties: + * + * - `$processor` (`OD_HTML_Tag_Processor`): The processor with the cursor at the current tag. + * - `$url_metric_group_collection` (`OD_URL_Metric_Group_Collection`): The URL Metrics which may include information about the current tag to inform what optimizations the callback performs. + * - `$link_collection` (`OD_Link_Collection`): Collection of links which will be added to the `HEAD` when the page is served. This allows you to add preload links and preconnect links as needed. + * + * Note that you are free to call `next_tag()` in the callback (such as to walk over any child elements) since the + * cursor will be reset to the tag after the callback finishes. + * + * A tag visitor callback returns a boolean value. When it returns `true`, then Optimization Detective will mark the + * tag as needing to be included among the elements stored in URL Metrics. The element data includes properties such + * as intersectionRatio, intersectionRect, and boundingClientRect as well as whether it is the LCP element. If the + * current tag is not relevant for the tag visitor or if the tag visitor callback does not need to query the provided + * `OD_URL_Metric_Group_Collection` instance to apply the desired optimizations, it can just return `false`. An + * element will be tracked in URL Metrics if _any_ tag visitor callback returns `true` when visiting the tag. + * + * Here's an example tag visitor that depends on URL Metrics data: + * + * $tag_visitor_registry->register( + * 'lcp-img-fetchpriority-high', + * static function ( OD_Tag_Visitor_Context $context ): bool { + * if ( $context->processor->get_tag() !== 'IMG' ) { + * return false; // Tag is not relevant for this tag visitor. + * } + * + * // Make sure fetchpriority=high is added to LCP IMG elements. + * $common_lcp_element = $context->url_metric_group_collection->get_common_lcp_element(); + * if ( + * null !== $common_lcp_element + * && + * $common_lcp_element->get_xpath() === $context->processor->get_xpath() + * ) { + * $context->processor->set_attribute( 'fetchpriority', 'high' ); + * } + * + * // Must return true so that the tag is included among the elements stored in URL Metrics. + * return true; + * } + * ); + * + * Please note this implementation of setting `fetchpriority=high` on the LCP `IMG` element is simplified. Please + * see the Image Prioritizer extension for a more robust implementation. + * + * Here's an example tag visitor that does not depend on any URL Metrics data: + * + * $tag_visitor_registry->register( + * 'img-decoding-async', + * static function ( OD_Tag_Visitor_Context $context ): bool { + * if ( $context->processor->get_tag() !== 'IMG' ) { + * return false; // Tag is not relevant for this tag visitor. + * } + * + * // Set the decoding attribute if it is absent. + * if ( null === $context->processor->get_attribute( 'decoding' ) ) { + * $context->processor->set_attribute( 'decoding', 'async' ); + * } + * + * // There's no need to query OD_URL_Metric_Group_Collection, so this element + * // doesn't need to be tracked in URL Metrics and the callback can return false. + * return false; + * } + * ); + * + * Refer to [Image Prioritizer](https://github.com/WordPress/performance/tree/trunk/plugins/image-prioritizer) and + * [Embed Optimizer](https://github.com/WordPress/performance/tree/trunk/plugins/embed-optimizer) for additional + * examples of how tag visitors are used. + * * @since 0.3.0 * * @param OD_Tag_Visitor_Registry $tag_visitor_registry Tag visitor registry.