Skip to content
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

Improve Optimization Detective documentation #1782

Merged
merged 11 commits into from
Feb 11, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,5 @@
* Exception thrown when failing to validate URL Metrics data.
*
* @since 0.1.0
* @access private
*/
final class OD_Data_Validation_Exception extends Exception {}
1 change: 0 additions & 1 deletion plugins/optimization-detective/class-od-element.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
* @todo The above implements tag should account for additional undefined keys which can be supplied by extending the element schema. May depend on <https://github.com/phpstan/phpstan/issues/8438>.
*
* @since 0.7.0
* @access private
*/
class OD_Element implements ArrayAccess, JsonSerializable {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
* Extension to WP_HTML_Tag_Processor that supports injecting HTML and obtaining XPath for the current tag.
*
* @since 0.1.1
* @access private
*/
final class OD_HTML_Tag_Processor extends WP_HTML_Tag_Processor {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
*
* @since 0.3.0
* @since 0.4.0 Renamed from OD_Preload_Link_Collection.
* @access private
*/
final class OD_Link_Collection implements Countable {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
* Context for tag visitors invoked for each tag while walking over a document.
*
* @since 0.4.0
* @access private
*
* @property-read OD_URL_Metric_Group_Collection $url_metrics_group_collection Deprecated property accessed via magic getter. Use the url_metric_group_collection property instead.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
* @implements IteratorAggregate<string, TagVisitorCallback>
*
* @since 0.3.0
* @access private
*/
final class OD_Tag_Visitor_Registry implements Countable, IteratorAggregate {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
* @implements IteratorAggregate<int, OD_URL_Metric_Group>
*
* @since 0.1.0
* @access private
*/
final class OD_URL_Metric_Group_Collection implements Countable, IteratorAggregate, JsonSerializable {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
* @implements IteratorAggregate<int, OD_URL_Metric>
*
* @since 0.1.0
* @access private
*/
final class OD_URL_Metric_Group implements IteratorAggregate, Countable, JsonSerializable {

Expand Down
1 change: 0 additions & 1 deletion plugins/optimization-detective/class-od-url-metric.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
* }
*
* @since 0.1.0
* @access private
*/
class OD_URL_Metric implements JsonSerializable {

Expand Down
16 changes: 16 additions & 0 deletions plugins/optimization-detective/helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
71 changes: 71 additions & 0 deletions plugins/optimization-detective/optimization.php
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not opposed to this block for now, but this is so detailed I think it should rather be part of some docs/*.md file. Maybe you can move (most of) it as part of #1857. This is probably relevant for one of the more detailed documentation articles to write, and we wouldn't want to have this much content duplicated between method docs and separate documentation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, as part of #1857 I'd love to have a process that would automatically extract the docs from phpdoc and dump it into the markdown files. That would ensure the documentation is as close to the code as possible (in PHP) while also being accessible for ease of reading (in Markdown).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While a code reference like that would be helpful, I think large text chunks like this one here still fit better into a more detailed article, e.g. on how to write an Optimization Detective extension.

We'd probably want to avoid duplicating too much between those "manual" articles and automatically generated code reference as well.

* 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.
westonruter marked this conversation as resolved.
Show resolved Hide resolved
*
* @since 0.3.0
*
* @param OD_Tag_Visitor_Registry $tag_visitor_registry Tag visitor registry.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ final class OD_Storage_Lock {
* Gets the TTL (in seconds) for the URL Metric storage lock.
*
* @since 0.1.0
* @access private
*
* @return int TTL in seconds, greater than or equal to zero. A value of zero means that the storage lock should be disabled and thus that transients must not be used.
*/
Expand Down Expand Up @@ -65,7 +64,6 @@ public static function get_transient_key(): string {
* seconds. Otherwise, if the current TTL is zero, then any transient is deleted.
*
* @since 0.1.0
* @access private
*/
public static function set_lock(): void {
$ttl = self::get_ttl();
Expand All @@ -81,7 +79,6 @@ public static function set_lock(): void {
* Checks whether URL Metric storage is locked (for the current IP).
*
* @since 0.1.0
* @access private
*
* @return bool Whether locked.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
* Context for when a URL Metric is successfully stored via the REST API.
*
* @since 0.7.0
* @access private
*/
final class OD_URL_Metric_Store_Request_Context {

Expand Down
Loading