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)
Maintainer thường phản hồi trong vòng 1 ngày
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 88/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- javascript, php
- Lĩnh vực
- backend, performance
Hướng nghiên cứu
Bắt đầu tại inc/rest.php quanh dòng 1032, nơi imageId của LCP được lưu qua sanitize_text_field(), sau đó kiểm tra Profile.php:385-393, nơi is_lcp_image_in_all_viewports() dùng === nghiêm ngặt. Tái hiện qua đoạn mã WP-CLI hoặc test hiện có test_lazyload_viewport_with_lcp_data, vốn hiện đang bỏ qua đường dẫn REST. Hoàn thành nghĩa là ID được lưu là int (hoặc được ép kiểu trước khi so sánh), phương thức trả về true cho cả hai cấu hình viewport, và nhánh LCP trong tag_replacer.php thêm fetchpriority="high".
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
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.
- Ngôn ngữ chính
- PHP
- Star
- 74
- Fork
- 14
- Merge trung bình
- 1 ngày 21 giờ
- Pull request đã merge (30 ngày)
- 30
Chuẩn bị môi trường
- Có Dockerfile hoặc tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của Codeinwp/optimole-wp
-
Page profiler endpoint fatals on PHP 8 when the request has no `b` (background selectors) fieldCó thể đã có người làm @girishpanchal30 đã nhận hôm nay. Đang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
Codeinwp/optimole-wp#1204 · 4 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Background image with a gradient is not lazy-loaded on WordPress 7.1 (Quote, Pullquote, Verse, Post Content, Accordion)Có thể đã có người làm @girishpanchal30 đã nhận hôm nay. Đang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Codeinwp/optimole-wp#1203 · 3 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Account sign-up fatals when the Optimole API returns an empty or non-JSON responseCó thể đã có người làm @girishpanchal30 đã nhận hôm nay. Đang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
Codeinwp/optimole-wp#1200 · 3 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Renaming an image leaves the old URL in comments and term descriptions, with "Unknown column 'ID'" database errorsCó thể đã có người làm @girishpanchal30 đã nhận 1 ngày trước. Đang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
Codeinwp/optimole-wp#1199 · 3 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug-report customer report
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 56/100
Codeinwp/optimole-wp#1211 ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của Codeinwp/optimole-wp
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
verbb/formie#3072 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 84/100
wp-graphql/wp-graphql-woocommerce#1026 ·
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
taskforcesh/bullmq#5038 ·
Maintainer thường phản hồi trong vòng 1 ngày