class-rum.php

Real-user Web Vitals (RUM) collection and reporting.

Source includes/Insight/class-rum.php15 min readPart of Performance Optimisation

includes/Insight/class-rum.php

Real-user Web Vitals (RUM) collection and reporting.

Namespace: PerformanceOptimise\\Inc · Lines: 3348

Class RUM

Collects real-visitor Core Web Vitals beacons and stores them as bounded per-day/per-path aggregates, plus the frontend beacon + admin data API.

Source: includes/Insight/class-rum.php, line 26

class RUM

Tags: @since 2.0.0

Constants

ConstantVisibilityValueLine
OPTIONpublic\'wppo_web_vitals_rum\'33
MAX_DAYSpublic1440
MAX_PATHS_PER_DAYpublic20047
MAX_TOTAL_PATHSpublic60059
MAX_OPTION_BYTESpublic49152067
RATE_LIMIT_PER_HOURpublic12074
GLOBAL_RATE_LIMIT_PER_MINUTEpublic12082
RUM_SAMPLE_RATE_DEFAULTpublic10093
RUM_THROTTLE_THRESHOLD_DEFAULTpublic60109
QUEUE_KEYprivate\'wppo_rum_queue\'117
FLUSH_LOCK_KEYprivate\'wppo_rum_flush_lock\'125
QUEUE_MAXprivate100133
MAX_LCP_URLS_PER_PATHpublic10144
MAX_LCP_SEGMENTS_PER_PATHpublic6155
MAX_LCP_SAMPLES_PER_SEGMENTpublic100166
MAX_INP_SEGMENTS_PER_PATHpublic6178
MAX_INP_SAMPLES_PER_SEGMENTpublic100189
LCP_URL_MAX_LENGTHpublic2048197
LCP_SELECTOR_MAX_LENGTHpublic256205
SLOW_RESOURCES_MAX_COUNTpublic5213
SLOW_RESOURCE_URL_MAX_LENGTHpublic2048221
SLOW_RESOURCE_MAX_DURATION_MSpublic60000229
MAX_LCP_SELECTORS_PER_PATHpublic10240
MAX_SLOW_RESOURCES_PER_PATHpublic10251
ALLOWED_SLOW_RESOURCE_TYPESpublicarray( \'img\', \'script\', \'css\', \'link\', \'font\', \'fetch\', \'xmlhttprequest\', \'iframe\' )262
ALLOWED_CONNECTIONSpublicarray( \'slow-2g\', \'2g\', \'3g\', \'4g\' )274
FIELD_LCP_DEFAULT_MIN_SAMPLESpublic20285
FIELD_LCP_MIN_SAMPLES_MAXpublic1000299
FIELD_LCP_STALE_TTLpublic86400311
FLUSH_THRESHOLDprivate20384

Properties

PropertyVisibilityTypeDefaultLine
$field_lcp_aggregateprivate static?arraynull325
$field_lcp_loadedprivate staticboolfalse333
$field_lcp_result_memoprivate staticarrayarray()342
$score_trends_memoprivate static?arraynull356
$score_trends_loadedprivate staticboolfalse364
$top_url_generationprivate staticint-1376
$stored_lcp_memoprivate staticarray<string,array()2867

publicstatic is_enabled()

public static function is_enabled(): bool

Whether RUM collection is enabled.

Return: bool.

Source: includes/Insight/class-rum.php, line 391

publicstatic clear_field_lcp_cache()

public static function clear_field_lcp_cache(): void

Clear the per-request field-LCP memo.

Return: void.

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 406

privatestatic top_url_generation()

private static function top_url_generation(): int

Current generation for the per-path top-URL index.

Return: int — Generation counter.

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 424

privatestatic top_url_cache_key()

private static function top_url_cache_key(string $normalized_path, int $min): string

Transient key for the per-path top-URL index entry.

ParameterTypeDefaultDescription
$normalized_pathstring—Normalized page path.
$minint—Sample gate.

Return: string — Transient key (unprefixed; wrap with Util::transient_key()).

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 444

privatestatic bump_top_url_generation()

private static function bump_top_url_generation(): void

Bump the top-URL index generation so flush-invalidated entries expire.

Return: void.

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 454

privatestatic get_memoized_aggregate()

private static function get_memoized_aggregate(): array

Get the RUM aggregate with a per-request memo.

Return: array — Aggregate data (empty array when missing/invalid).

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 471

privatestatic ensure_field_lcp_cache_hook()

private static function ensure_field_lcp_cache_hook(): void

Register invalidation hooks for the RUM aggregate memo (once per request).

Return: void.

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 491

publicstatic migrate_rum_autoload()

public static function migrate_rum_autoload(): void

Migrate the RUM aggregate option to non-autoloading.

Return: void.

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 512

publicstatic collect()

public static function collect(array $params): array

Handle a RUM beacon.

ParameterTypeDefaultDescription
$paramsarray—Decoded JSON body from the beacon request.

Return: array{ok:bool,status:int,message:string}.

Source: includes/Insight/class-rum.php, line 535

publicstatic get_data()

public static function get_data(): array

Retrieve the aggregated RUM data for the admin dashboard.

Return: array.

Source: includes/Insight/class-rum.php, line 603

publicstatic get_aggregate_readonly()

public static function get_aggregate_readonly(): array

Retrieve the aggregated RUM data without side effects (read-only).

Return: array — Aggregate data (empty array when missing/invalid).

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 624

publicstatic maybe_enqueue_scripts()

public static function maybe_enqueue_scripts(): void

Enqueue the frontend beacon script on the public site.

Return: void.

Source: includes/Insight/class-rum.php, line 647

privatestatic supports_script_strategy()

private static function supports_script_strategy(): bool

Whether core supports the native `strategy` script args (WP 6.3+).

Return: bool.

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 713

publicstatic print_config()

public static function print_config(): void

Print the beacon config inline so it is baked into cached HTML.

Return: void.

Source: includes/Insight/class-rum.php, line 732

privatestatic detect_template_slug()

private static function detect_template_slug(): string

Detect the current template slug for RUM segmentation.

Return: string — Template slug (max 64 chars) or \’\’.

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 791

privatestatic token_for()

private static function token_for(int $timestamp, string=\'/\' $path): string

Rolling daily token for the beacon, scoped to the page path.

ParameterTypeDefaultDescription
$timestampint—Unix timestamp.
$pathstring=\'/\'—Page path the token is minted for.

Return: string.

Tags: @since 2.0.0 The $path parameter was added.

Source: includes/Insight/class-rum.php, line 828

privatestatic is_valid_token()

private static function is_valid_token(string $token, string=\'/\' $path): bool

Validate the beacon token against today or yesterday for the given path.

ParameterTypeDefaultDescription
$tokenstring—Beacon token.
$pathstring=\'/\'—Page path the beacon was served on.

Return: bool.

Tags: @since 2.0.0 The $path parameter was added.

Source: includes/Insight/class-rum.php, line 841

privatestatic is_rate_limited()

private static function is_rate_limited(string $ip): bool

Whether the given IP has exceeded the hourly beacon budget.

ParameterTypeDefaultDescription
$ipstring—Client IP address.

Return: bool.

Source: includes/Insight/class-rum.php, line 865

privatestatic normalize_ip()

private static function normalize_ip(string $ip): string

Normalize a client IP for rate-limit keying.

ParameterTypeDefaultDescription
$ipstring—Raw IP string.

Return: string — Normalized IP or \’\’.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 886

privatestatic is_globally_rate_limited()

private static function is_globally_rate_limited(): bool

Whether the site-wide per-minute beacon budget is exhausted.

Return: bool.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 912

publicstatic get_sample_rate()

public static function get_sample_rate(): int

Configured RUM beacon sample rate (percent of page views, 1-100).

Return: int — Sample rate in 1-100.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 963

publicstatic get_effective_sample_rate()

public static function get_effective_sample_rate(): int

Effective sample rate after the high-traffic auto-throttle.

Return: int — Effective rate in 1-100.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1012

publicstatic should_keep_sample()

public static function should_keep_sample(?int=null $rate, ?int=null $roll): bool

Sampling decision for one beacon (lossy hint only, no PII).

ParameterTypeDefaultDescription
$rate?int=null—Sample rate in 1-100. Null resolves via get_effective_sample_rate().
$roll?int=null—Deterministic roll in 1-100. Null draws fresh randomness.

Return: bool — True when the beacon should be sent/stored.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1066

privatestatic sanitize_sample()

private static function sanitize_sample(array $params): ?array

Validate and clamp a beacon sample.

ParameterTypeDefaultDescription
$paramsarray—Raw beacon payload.

Return: array|null — Normalized sample or null when invalid.

Source: includes/Insight/class-rum.php, line 1100

publicstatic get_metric_ranges()

public static function get_metric_ranges(): array

Shared metric range table for sample validation.

Return: array<string,array{0:float,1:float}> — Metric => [min, max].

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1216

privatestatic clamp_metric_value()

private static function clamp_metric_value(string $metric, float $value): float

Clamp a metric value to its valid range.

ParameterTypeDefaultDescription
$metricstring—Metric name.
$valuefloat—Raw value (must be finite).

Return: float — Clamped value.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1236

privatestatic normalize_segment()

private static function normalize_segment($raw, ?array $allowlist, int $maxlen): string

Normalize a raw segment value against an allowlist.

ParameterTypeDefaultDescription
$rawmixed—Raw value.
$allowlist?array—Allowed values (null = free-form slug).
$maxlenint—Max length before normalization.

Return: string — Normalized segment or \’unknown\’.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1256

privatestatic get_home_host()

private static function get_home_host(): string

Resolve the home host (lowercased) for same-origin checks.

Return: string — Home host or \’\’.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1281

privatestatic is_scheme_like_url()

private static function is_scheme_like_url(string $url): bool

Whether a URL is scheme-like (can never be same-origin relative).

ParameterTypeDefaultDescription
$urlstring—Candidate URL.

Return: bool — True when scheme-like.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1304

privatestatic normalize_segment_device()

private static function normalize_segment_device($raw): string

Normalize a device value to the segment allowlist.

ParameterTypeDefaultDescription
$rawmixed—Raw device value.

Return: string — Allowlisted device or \’unknown\’.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1329

privatestatic normalize_segment_template()

private static function normalize_segment_template($raw): string

Normalize a template slug to the segment allowlist shape.

ParameterTypeDefaultDescription
$rawmixed—Raw template value.

Return: string — Sanitized template slug (max 64 chars) or \’unknown\’.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1344

privatestatic normalize_segment_connection()

private static function normalize_segment_connection($raw): string

Normalize a queued-sample connection value to the segment allowlist.

ParameterTypeDefaultDescription
$rawmixed—Raw connection value from a queued sample.

Return: string — Allowlisted connection type or \’unknown\’.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1360

privatestatic sanitize_lcp_selector()

private static function sanitize_lcp_selector($raw): string

Sanitize an LCP element selector attribution value.

ParameterTypeDefaultDescription
$rawmixed—Raw selector value.

Return: string — Sanitized selector or \’\’.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1380

privatestatic normalize_slow_resource_type()

private static function normalize_slow_resource_type($raw): string

Normalize a slow-resource initiator type to the allowlist.

ParameterTypeDefaultDescription
$rawmixed—Raw initiator type.

Return: string — Allowlisted type or \’\’.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1417

privatestatic sanitize_slow_resources()

private static function sanitize_slow_resources($raw): array

Sanitize the slow-resource audit payload.

ParameterTypeDefaultDescription
$rawmixed—Raw slowResources value.

Return: array — Shaped entries (possibly empty).

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1447

privatestatic is_safe_lcp_url()

private static function is_safe_lcp_url(string $lcp_url): bool

Whether a candidate LCP element URL is safe to store.

ParameterTypeDefaultDescription
$lcp_urlstring—Candidate LCP URL (already trimmed + length-capped).

Return: bool — True when safe to store.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1512

privatestatic is_same_origin_lcp_url()

private static function is_same_origin_lcp_url(string $lcp_url): bool

Whether an LCP element URL is same-origin with this site.

ParameterTypeDefaultDescription
$lcp_urlstring—Candidate LCP URL.

Return: bool — True when same-origin.

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 1556

publicstatic is_same_origin_url()

public static function is_same_origin_url(string $url): bool

Whether a URL is same-origin with this site (public emission guard).

ParameterTypeDefaultDescription
$urlstring—Candidate URL.

Return: bool — True when same-origin or unverifiable.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1592

publicstatic is_same_origin_url_strict()

public static function is_same_origin_url_strict(string $url): bool

Whether a URL is same-origin, strict variant for emission paths.

ParameterTypeDefaultDescription
$urlstring—Candidate URL.

Return: bool — True only when same-origin is positively proven.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1637

privatestatic has_ext_object_cache()

private static function has_ext_object_cache(): bool

Whether a persistent external object cache is available.

Return: bool — True when wp_using_ext_object_cache() reports a persistent cache.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1683

privatestatic append_to_queue_atomic()

private static function append_to_queue_atomic(array $sample): array

Atomically append a sample to the RUM queue.

ParameterTypeDefaultDescription
$samplearray—Normalized sample (with `_ts` attached).

Return: array{0:bool,1:int} — Tuple of (was_empty before append, count after append).

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1711

privatestatic acquire_flush_lock()

private static function acquire_flush_lock(): bool

Atomically acquire the RUM flush lock.

Return: bool — True when this worker owns the lock.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1795

privatestatic release_flush_lock()

private static function release_flush_lock(): void

Release the RUM flush lock from both namespaces.

Return: void.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1837

privatestatic merge_value_segment()

private static function merge_value_segment(array& $bucket, string $map_key, int $max_segments, int $max_samples, string $device, string $template, string $connection, float $value): void

Merge one value into a bounded per-path segment map.

ParameterTypeDefaultDescription
$bucketarray&—Bucket to merge into (by ref).
$map_keystring—Segment map key (\’lcpSeg\’ or \’inpSeg\’).
$max_segmentsint—Max segments per path.
$max_samplesint—Max reservoir samples per segment.
$devicestring—Normalized device.
$templatestring—Normalized template.
$connectionstring—Normalized connection.
$valuefloat—Clamped metric value.

Return: void.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1873

privatestatic validate_queued_sample()

private static function validate_queued_sample($sample): ?array

Validate one queued sample into a merge-ready shape.

ParameterTypeDefaultDescription
$samplemixed—Raw queued entry.

Return: array{date:string,path:string,ts:int,sample:array}|null — Validated sample or null to skip.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1930

privatestatic persist_aggregate()

private static function persist_aggregate(array $all): void

Persist aggregates with retention + size budgets.

ParameterTypeDefaultDescription
$allarray—Aggregates.

Return: void.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 1963

privatestatic store_sample()

private static function store_sample(array $sample): void

Buffer a sample to a transient queue and flush periodically.

ParameterTypeDefaultDescription
$samplearray—Normalized sample.

Return: void.

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 2025

publicstatic flush_queue()

public static function flush_queue(): void

Flush queued RUM samples to the persistent aggregate option.

Return: void.

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 2066

publicstatic get_field_lcp_url()

public static function get_field_lcp_url(?string=null $path): ?array

Get the field-measured LCP URL for a page path.

ParameterTypeDefaultDescription
$path?string=null—Page path (e.g. \”/about/\”). Defaults to the current request path.

Return: array{url:string,n:int,lastSeen:int}|null — Top LCP URL entry or null.

Tags: @since 2.0.0 · @since 2.2.0 Sample gate unified via get_field_lcp_min_samples() so `ai_adaptive.field_lcp_min_samples` is honoured.

Source: includes/Insight/class-rum.php, line 2410

publicstatic get_lcp_preload_candidate()

public static function get_lcp_preload_candidate(?string=null $path): ?array

Get the single LCP preload candidate for a page path.

ParameterTypeDefaultDescription
$path?string=null—Page path (e.g. \”/about/\”). Defaults to the current request path.

Return: array{url:string,n:int,lastSeen:int}|null — Single LCP candidate or null.

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 2602

publicstatic get_top_lcp_selector()

public static function get_top_lcp_selector(?string=null $path, ?int=null $min): ?array

Get the top LCP element selector attribution for a page path.

ParameterTypeDefaultDescription
$path?string=null—Page path (e.g. \”/about/\”). Defaults to the current request path.
$min?int=null—Minimum samples (defaults to get_field_lcp_min_samples()).

Return: array{selector:string,n:int,lastSeen:int}|null — Top selector or null.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 2645

publicstatic get_top_slow_resources()

public static function get_top_slow_resources(int=3 $limit): array

Get the top slow-resource audit entries across the aggregate.

ParameterTypeDefaultDescription
$limitint=3—Maximum entries (1–10, defaults to 3).

Return: array<int,array{url:string,type:string,n:int,avgDuration:float,maxDuration:float,lastSeen:int}> — Top slow resources.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 2750

privatestatic resolve_current_path()

private static function resolve_current_path(): ?string

Resolve the current page path the same way the preload pipeline does.

Return: string|null — Current page path or null when unresolvable.

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 2847

publicstatic clear_stored_lcp_memo()

public static function clear_stored_lcp_memo(): void

Clear the per-request stored-LCP memo.

Return: void.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 2878

privatestatic memo_store_lcp()

private static function memo_store_lcp(string $memo_key, string $value): void

Store one memo entry with a drop-oldest cap.

ParameterTypeDefaultDescription
$memo_keystring—Memo bucket key.
$valuestring—LCP URL (or \’\’ for a negative).

Return: void.

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 2893

publicstatic get_stored_pagespeed_lcp_url()

public static function get_stored_pagespeed_lcp_url(?string=null $path): string

Read-only lookup of the stored PageSpeed LCP candidate for a page.

ParameterTypeDefaultDescription
$path?string=null—Page path (e.g. \”/about/\”). Defaults to the current request URL.

Return: string — The PageSpeed LCP image URL, or empty string when none is stored.

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 2922

publicstatic get_field_lcp_min_samples()

public static function get_field_lcp_min_samples(): int

Resolve the field-LCP minimum-sample threshold for auto-tune.

Return: int — Minimum samples (>=1).

Tags: @since 2.0.0 · @since 2.2.0 Return value is clamped to 1–FIELD_LCP_MIN_SAMPLES_MAX.

Source: includes/Insight/class-rum.php, line 3049

publicstatic compute_p75()

public static function compute_p75(array $samples): float

Compute the p75 of a numeric sample list.

ParameterTypeDefaultDescription
$samplesarray—Numeric samples.

Return: float — p75 value or 0.0 when empty.

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 3078

publicstatic get_field_p75_by_segment()

public static function get_field_p75_by_segment(string $seg_key, ?int=null $min_samples): array

Get field p75 segmented by device × template × connection (read-only).

ParameterTypeDefaultDescription
$seg_keystring—Segment map key (\’lcpSeg\’ or \’inpSeg\’).
$min_samples?int=null—Minimum samples per segment. Null resolves via get_field_lcp_min_samples().

Return: array[] — Rows of array(path,device,template,connection,n,p75).

Tags: @since 2.2.0

Source: includes/Insight/class-rum.php, line 3103

publicstatic get_field_lcp_p75_by_segment()

public static function get_field_lcp_p75_by_segment(?int=null $min_samples): array

Get field LCP p75 segmented by device × template × connection (read-only).

ParameterTypeDefaultDescription
$min_samples?int=null—Minimum samples per segment. Null resolves via get_field_lcp_min_samples().

Return: array[] — Rows of array(path,device,template,connection,n,p75).

Tags: @since 2.0.0 · @since 2.2.0 Added the `connection` segment dimension.

Source: includes/Insight/class-rum.php, line 3208

publicstatic get_path_lcp_priority()

public static function get_path_lcp_priority(?int=null $min_samples): array

Get worst p75 LCP per normalized path for CSS queue prioritization.

ParameterTypeDefaultDescription
$min_samples?int=null—Minimum samples per segment. Null resolves via get_field_lcp_min_samples().

Return: array<string, — float> Normalized path => worst p75 LCP in ms, worst-first order.

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 3228

publicstatic score_url_lcp()

public static function score_url_lcp(string $url, ?array=null $priority, ?array=null $trends): float

Score a queue URL by worst p75 LCP (RUM path + trend blend).

ParameterTypeDefaultDescription
$urlstring—Candidate queue URL.
$priority?array=null——
$trends?array=null—Optional pre-loaded Pagespeed::get_trends() map. Null loads (and per-request memos) it once.

Return: float — Worst p75 LCP in ms, or 0.0 when unknown.

Tags: @since 2.0.0

Source: includes/Insight/class-rum.php, line 3269

publicstatic get_field_inp_p75_by_segment()

public static function get_field_inp_p75_by_segment(?int=null $min_samples): array

Get field INP p75 segmented by device × template × connection (read-only).

ParameterTypeDefaultDescription
$min_samples?int=null—Minimum samples per segment. Null resolves via get_field_lcp_min_samples() (shared gate, default 20).

Return: array[] — Rows of array(path,device,template,connection,n,p75).

Tags: @since 2.0.0 · @since 2.2.0 Added the `connection` segment dimension.

Source: includes/Insight/class-rum.php, line 3344

Hooks

Hooks referenced in includes/Insight/class-rum.php:

HookTypeLineNotes
wppo_rum_throttle_thresholdfilter1018—
wppo_rum_effective_sample_ratefilter1029—