Make WordPress Core

Opened 2 months ago

Closed 10 days ago

Last modified 6 days ago

#58893 closed enhancement (fixed)

Introduce filter to modify/override attributes returned by `wp_get_loading_optimization_attributes()`

Reported by: flixos90's profile flixos90 Owned by: pereirinha's profile pereirinha
Milestone: 6.4 Priority: normal
Severity: normal Version: 6.3
Component: Media Keywords: has-patch, changes-requested, needs-dev-note
Focuses: performance Cc:

Description

The wp_get_loading_optimization_attributes() function introduced in 6.3 (see #58235) provides a central place to get loading optimization attributes for specific elements/tags.

Currently, it is impossible for plugins to customize that logic, which is a limitation given that plugins may use alternative ways that e.g. can predict in-viewport elements or the LCP element more reliably than WordPress core.

A filter should be introduced that allows to change the returned attributes: Either before returning the attributes array, or alternatively as a short-circuit filter - or potentially both? Let's discuss.

This ticket's implementation should be considered blocked by #58891 as making the changes before that would be unnecessarily complicated and error-prone.

Change History (27)

#1 @joemcgill
2 months ago

I noted a similar thing in #58895. Should we consolidate these two tickets, or focus mine on the specific rendered markup functions called in wp_filter_content_tags()?

#2 @flixos90
2 months ago

With [56347] committed, this effort is now unblocked. Please refer to the latest codebase for any changes to wp_get_loading_optimization_attributes().

#3 @flixos90
2 months ago

  • Owner set to pereirinha
  • Status changed from new to assigned

#4 @pereirinha
5 weeks ago

@flixos90

I think both filters make sense, as there are valid use cases for both.

Someone might want to implement its custom logic for the optimization attributes — a short circuit early access is ideal as it prevents running lots of code that won't be needed — others just tweak one of the values — so the later, the better.

If we agree, I'll proceed with the 2 filters.

Perhaps a wp_pre_get_loading_optimization_attributes and a wp_get_loading_optimization_attributes filter.

#5 @flixos90
5 weeks ago

@pereirinha Your idea sounds good to me, +1 for implementing one pre_ and another regular (post) filter.

This ticket was mentioned in Slack in #core-performance by pereirinha. View the logs.


5 weeks ago

This ticket was mentioned in Slack in #core-performance by pereirinha. View the logs.


4 weeks ago

This ticket was mentioned in Slack in #core-performance by pereirinha. View the logs.


4 weeks ago

This ticket was mentioned in PR #5176 on WordPress/wordpress-develop by @pereirinha.


3 weeks ago
#9

  • Keywords has-patch added

This PR adds 2 filters.

The first one, wp_pre_get_loading_optimization_attributes, allows short-circuiting the core logic, whereas wp_get_loading_optimization_attributes allows filtering the core logic.

Trac ticket: https://core.trac.wordpress.org/ticket/58893

This ticket was mentioned in Slack in #core-performance by pereirinha. View the logs.


3 weeks ago

This ticket was mentioned in Slack in #core-performance by flixos90. View the logs.


3 weeks ago

@mukesh27 commented on PR #5176:


13 days ago
#12

@pereirinha, could you kindly address the feedback provided above and rebase the PR? It's worth noting that https://core.trac.wordpress.org/ticket/58894 was merged yesterday, so this may require some adjustments.

@mukesh27 commented on PR #5176:


13 days ago
#13

@pereirinha Could you please update code and unit tests as suggested below?

Add pre_wp_get_loading_optimization_attributes filter code after line 5628. and remove your changes for this filter.

/**
 * Filters whether to short-circuit loading optimization attributes.
 *
 * Returning an array from the filter will effectively short-circuit the loading of optimization attributes,
 * returning that value instead.
 *
 * @since 6.4.0
 *
 * @param array  $loading_attrs The loading optimization attributes.
 * @param string $tag_name      The tag name.
 * @param array  $attr          Array of the attributes for the tag.
 * @param string $context       Context for the element for which the loading optimization attribute is requested.
 */
$loading_attrs = apply_filters( 'pre_wp_get_loading_optimization_attributes', $loading_attrs, $tag_name, $attr, $context );

if ( ! empty( $loading_attrs ) ) {
	return $loading_attrs;
}

Unit tests:

/**
 * Tests for pre_wp_get_loading_optimization_attributes filter.
 *
 * @ticket 58893
 */
public function test_pre_wp_get_loading_optimization_attributes_filter() {
	add_filter(
		'pre_wp_get_loading_optimization_attributes',
		static function ( $loading_attrs ) {
			$loading_attrs['fetchpriority'] = 'high';
			return $loading_attrs;
		},
		10,
		1
	);

	$attr = $this->get_width_height_for_high_priority();

	$this->assertSame(
		array( 'fetchpriority' => 'high' ),
		wp_get_loading_optimization_attributes( 'img', $attr, 'the_content' ),
		'The filter did not return early fetchpriority attribute'
	);

	// Clean up the filter.
	add_filter( 'pre_wp_get_loading_optimization_attributes', '__return_empty_array' );

	// Modify the loading attributes with any custom attributes.
	add_filter(
		'pre_wp_get_loading_optimization_attributes',
		static function ( $loading_attrs ) {
			$loading_attrs['custom_attr'] = 'custom_value';
			return $loading_attrs;
		},
		10,
		1
	);

	$this->assertSame(
		array( 'custom_attr' => 'custom_value' ),
		wp_get_loading_optimization_attributes( 'img', $attr, 'the_content' ),
		'The filter did not return custom attributes.'
	);
}

/**
 * Tests for wp_get_loading_optimization_attributes filter.
 *
 * @ticket 58893
 */
public function test_wp_get_loading_optimization_attributes_filter() {
	$attr = $this->get_width_height_for_high_priority();

	$this->assertSame(
		array( 'loading' => 'lazy' ),
		wp_get_loading_optimization_attributes( 'img', $attr, 'the_content' ),
		'Before the filter it will not return the loading attribute.'
	);

	add_filter(
		'wp_get_loading_optimization_attributes',
		static function ( $loading_attrs ) {
			unset( $loading_attrs['loading'] );
			$loading_attrs['fetchpriority'] = 'high';
			return $loading_attrs;
		},
		10,
		1
	);

	$this->assertSame(
		array( 'fetchpriority' => 'high' ),
		wp_get_loading_optimization_attributes( 'img', $attr, 'the_content' ),
		'After the filter it will not return the fetchpriority attribute.'
	);
}

#14 @mukesh27
13 days ago

  • Keywords changes-requested added; 2nd-opinion removed
  • Version set to 6.3

@pereirinha, could you please review the suggested changes on the PR? This will help us move forward with this ticket and commit it before the Beta release

This ticket was mentioned in Slack in #core-performance by flixos90. View the logs.


12 days ago

@pereirinha commented on PR #5176:


12 days ago
#16

Thanks again, @mukeshpanchal27, @felixarntz, and @spacedmonkey, for the feedback.

I addressed all the comments so far.
This is ready for you to circle back.

@pereirinha commented on PR #5176:


12 days ago
#17

Thanks, @mukeshpanchal27, for the clarification on the outstanding issue.
I merged your code, and I'm running tests locally to confirm, but this should now be ready.

@pereirinha commented on PR #5176:


11 days ago
#18

One small piece of feedback. But this is close.

Thanks @spacedmonkey. I haven't encountered the assertSameSets before, but it is excellent for the other ticket I'm working on.

For this case, given that we are expecting only one key in the array, I wonder if it will make any real difference.

@spacedmonkey commented on PR #5176:


11 days ago
#19

For this case, given that we are expecting only one key in the array, I wonder if it will make any real difference.

If that is the case we should something like this.

$attrs = wp_get_loading_optimization_attributes( 'img', $attr, 'the_content' );
$this->assertIsArray( $attrs );
$this->assertArrayHasKey( 'custom_attr', $attrs );
$this->assertSame( 'custom_attr', $filtered_widgets['custom_attr'] );

@flixos90 commented on PR #5176:


11 days ago
#20

@spacedmonkey @pereirinha Apologies, I didn't see your discussion here and just applied the suggestions. While I agree it's not a real issue here, using assertSameSets is generally a bit cleaner when doing assertions on associative arrays, since the order doesn't matter. So for one item it doesn't make a difference, but it's still "more correct" to use assertSameSets just because it is an associative array - e.g. in case the tests were to be adjusted later.

@pereirinha commented on PR #5176:


10 days ago
#21

I got some notifications that Felix had merged https://github.com/WordPress/wordpress-develop/commit/896b25e63fa057e7902613ba17a3789338f1d4e5. I thought this was revolving everything outstanding.

Is there still an action item pending here?

@flixos90 commented on PR #5176:


10 days ago
#22

@pereirinha All good, I'm about to commit this.

Once I have committed it, can you refresh your branch from #4991 with the latest trunk to integrate the changes, in case there are any merge conflicts?

#23 @flixos90
10 days ago

  • Resolution set to fixed
  • Status changed from assigned to closed

In 56651:

Media: Introduce filters to customize the results from wp_get_loading_optimization_attributes().

This changeset introduces two filters that allow customizing the loading optimization attributes array returned from wp_get_loading_optimization_attributes() for individual HTML tags:

  • The wp_get_loading_optimization_attributes filter can be used to modify the results from the WordPress core logic.
  • The pre_wp_get_loading_optimization_attributes filter can be used to use entirely custom logic and effectively short-circuit the core function.

Props pereirinha, mukesh27, spacedmonkey, joemcgill.
Fixes #58893.

#25 @thekt12
7 days ago

#58895 was marked as a duplicate.

This ticket was mentioned in Slack in #core-performance by thekt12. View the logs.


7 days ago

#27 @flixos90
6 days ago

  • Keywords needs-dev-note added

The 4 tickets related to wp_get_loading_optimization_attributes() should receive a single dev note post explaining those changes.

Note: See TracTickets for help on using tickets.