Page profiler never treats the detected LCP image as LCP, so it gets no fetchpriority="high" (stored ID is a string, compared with === to an int)
I maintainer di solito rispondono entro 1 giorno
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 88/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- javascript, php
- Ambito
- backend, performance
Direzione di ricerca
Inizia da inc/rest.php intorno alla riga 1032, dove l’imageId LCP viene memorizzato tramite sanitize_text_field(), poi esamina Profile.php:385-393 dove is_lcp_image_in_all_viewports() usa === strict. Riproduci tramite lo snippet WP-CLI o il test esistente test_lazyload_viewport_with_lcp_data, che attualmente bypassa il percorso REST. Fatto significa che l’ID memorizzato è un int (o viene castato prima del confronto), il metodo restituisce true per entrambi i profili viewport, e il ramo LCP di tag_replacer.php aggiunge fetchpriority="high".
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Description
The page profiler detects the LCP image in the browser and sends its data-opt-id to /optimizations as an integer. The REST handler stores it with sanitize_text_field(), which always returns a string. Profile::is_lcp_image_in_all_viewports( int $image_id ) then compares that string to the int ID with ===, so it is always false.
Result, with the default "fixed|viewport" lazy load type and profile data stored for both devices:
- Optimole never adds
fetchpriority="high"to the LCP image (tag_replacer.phpLCP branch is dead, and the fixed-count fallback is skipped because profile data exists). - If the LCP image is not in the above-the-fold list for both devices, it is lazy-loaded anyway (and any
fetchpriority="high"on it is stripped).
Expected: the stored LCP image gets fetchpriority="high" and is never lazy-loaded. Likely fix: store absint( $lcp_data['i'] ?? 0 ) in inc/rest.php (or cast before comparing in Profile.php). Existing profiles in transients/object cache keep the string until they expire, so casting at compare time also covers those.
The unit test test_lazyload_viewport_with_lcp_data stores imageId as an int directly through Profile::store(), so it does not cover the REST path.
Step-by-step reproduction instructions
- On a test site with Optimole 4.2.17 connected and default Lazy Load settings, run this with WP-CLI (it stores LCP data the same way
inc/rest.php:1032does):wp eval ' $p = new OptimoleWP\PageProfiler\Profile(); $img = 1578474861; $lcp = [ "imageId" => sanitize_text_field( $img ), "type" => "img" ]; foreach ( [ 1, 2 ] as $d ) { $p->store( "bugcheck", $d, [], [], $lcp ); } OptimoleWP\PageProfiler\Profile::set_current_profile_id( "bugcheck" ); $p->set_current_profile_data(); var_dump( $p->is_lcp_image_in_all_viewports( $img ) ); ' - Expected
bool(true). Actualbool(false). - Clean up:
wp transient delete _oprof_bugcheck_1 && wp transient delete _oprof_bugcheck_2(or flush theoptimole_page_profilercache group if an object cache is used).
End to end check on a real page: open a page with a large hero image once on desktop and once in mobile emulation so both profiles are stored, then reload and view source. The hero <img data-opt-id=...> has no fetchpriority="high" added by Optimole, and wp transient get _oprof_<profile id>_2 --format=json shows "imageId":"<id>" as a string.
Pure PHP reproduction of the same path (json_decode of the REST body, core _sanitize_text_fields cast, transient serialize round trip, the Profile.php:387 comparison), PHP 8.4:
REST param l.i type: integer
[transient] stored imageId='1578474861' (string), page image_id=1578474861 (integer) -> is_lcp_image_in_all_viewports=false; loose == would be true
[object-cache-json] stored imageId='1578474861' (string), page image_id=1578474861 (integer) -> is_lcp_image_in_all_viewports=false; loose == would be true
Screenshots, screen recording, code snippet or Help Scout ticket
Browser sends an int: https://github.com/Codeinwp/optimole-wp/blob/v4.2.17/assets/js/modules/lcp.js#L88-L92
lcpData.imageId = parseInt(id, 10);
REST handler stores a string: https://github.com/Codeinwp/optimole-wp/blob/v4.2.17/inc/rest.php#L1032
$sanitized_lcp_data['imageId'] = sanitize_text_field( $lcp_data['i'] ?? '' );
Strict compare with the int data-opt-id: https://github.com/Codeinwp/optimole-wp/blob/v4.2.17/inc/v2/PageProfiler/Profile.php#L385-L393
public function is_lcp_image_in_all_viewports( int $image_id ): bool {
...
( ( self::$current_profile_data[ $device ]['lcp']['imageId'] ?? null ) === $image_id )
Callers that never fire:
- https://github.com/Codeinwp/optimole-wp/blob/v4.2.17/inc/tag_replacer.php#L434-L445 (adds
fetchpriority="high") - https://github.com/Codeinwp/optimole-wp/blob/v4.2.17/inc/lazyload_replacer.php#L464-L480 (skips lazy load for the LCP image)
$image_id comes from get_id_by_url(), which returns rand() (an int): https://github.com/Codeinwp/optimole-wp/blob/v4.2.17/inc/app_replacer.php#L691-L697
Core: _sanitize_text_fields() casts to string: https://github.com/WordPress/WordPress/blob/7.1.3/wp-includes/formatting.php#L5708-L5713
Environment info
- Optimole 4.2.17 (same code on
masterand back to 4.0.0) - WordPress 5.5 to 7.1 (
_sanitize_text_fields()casts to string in 5.5, 6.8.3 and 7.1.3) - PHP 7.4 to 8.4 (strict
===behaves the same on all) - Lazy load type "fixed|viewport" (default), page profiler enabled (default)
Is the issue you are reporting a regression
No. The string store and the strict compare are both present in 4.0.0.
Found while writing the WordPress compatibility checks for Optimole.
- Lingua principale
- PHP
- Stelle
- 74
- Fork
- 14
- Merge medio
- 1g 22h
- PR unite (30g)
- 29
Preparare l'ambiente
- Include un Dockerfile o un file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di Codeinwp/optimole-wp
-
Page profiler endpoint fatals on PHP 8 when the request has no `b` (background selectors) fieldForse già presa @girishpanchal30 l’ha presa 1 giorno fa. Apertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
Codeinwp/optimole-wp#1204 · 4 commenti · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
Background image with a gradient is not lazy-loaded on WordPress 7.1 (Quote, Pullquote, Verse, Post Content, Accordion)Forse già presa @girishpanchal30 l’ha presa 1 giorno fa. Apertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
Codeinwp/optimole-wp#1203 · 3 commenti · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
Account sign-up fatals when the Optimole API returns an empty or non-JSON responseForse già presa @girishpanchal30 l’ha presa 1 giorno fa. Apertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
Codeinwp/optimole-wp#1200 · 3 commenti · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
Renaming an image leaves the old URL in comments and term descriptions, with "Unknown column 'ID'" database errorsForse già presa @girishpanchal30 l’ha presa 1 giorno fa. Apertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
Codeinwp/optimole-wp#1199 · 3 commenti · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
bug-report customer report
Difficoltà 4/5 3-5 giorni Idoneità per principianti 56/100
Codeinwp/optimole-wp#1211 ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di Codeinwp/optimole-wp
Issue simili
-
C-CDA export: allergy concern act code, policy activity translation and empty id/@extension fail conformanceForse già presa @doctorman l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
-
help wanted
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 82/100
-
scope:testing status:unconfirmed
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
wp-cli/wp-cli-tests#389 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
the-benchmarker/web-frameworks#10153 ·
I maintainer di solito rispondono entro 1 giorno