@@ -566,7 +566,7 @@ async function runBootProbe(phase: string, bucket: R2Bucket): Promise<Response>
566566 }
567567 }
568568
569- if ( [ "canonical-current-user" , "canonical-init" , "canonical-site-status" , "canonical-wp-loaded" ] . includes ( phase ) ) {
569+ if ( [ "canonical-current-user" , "canonical-init" , "canonical-site-status" , "canonical-wp-loaded" , "canonical-wp-loaded-callbacks" , "canonical-wp-loaded-exclude-rewrite-flush" , "canonical-wp-loaded-exclude-core-template-header" , "canonical-wp-loaded-exclude-playground" , "canonical-wp-loaded-exclude-wp-cron" , "canonical-wp-loaded-exclude-all" ] . includes ( phase ) ) {
570570 const runtime = await bootWordPressRuntime ( "do-not-attempt-installing" , true , true , undefined , await packagedCanonicalMarkdownSeed ( ) , new Uint8Array ( markdownPrimaryBootstrapIndex ) , "https://canonical-probe.invalid" , { } , bucket , true )
571571 try {
572572 const evidence = ( await runtime . php . run ( { code : canonicalLifecycleProbeCode ( phase ) } ) ) . text . trim ( )
@@ -1004,15 +1004,81 @@ require '/wordpress/wp-load.php';`
10041004}
10051005
10061006function canonicalLifecycleProbeCode ( phase : string ) : string {
1007+ const wpLoadedExclusions : Record < string , { identifiers : string [ ] ; retain : boolean } > = {
1008+ "canonical-wp-loaded-exclude-rewrite-flush" : { identifiers : [ "WP_Rewrite::flush_rules" , "playground_maybe_flush_rewrite_rules" ] , retain : false } ,
1009+ "canonical-wp-loaded-exclude-core-template-header" : { identifiers : [ "_add_template_loader_filters" , "_custom_header_background_just_in_time" , "_custom_logo_header_styles" ] , retain : false } ,
1010+ "canonical-wp-loaded-exclude-playground" : { identifiers : [ "playground_maybe_flush_rewrite_rules" , "playground_save_wp_env_info" ] , retain : false } ,
1011+ "canonical-wp-loaded-exclude-wp-cron" : { identifiers : [ "_wp_cron" ] , retain : false } ,
1012+ "canonical-wp-loaded-exclude-all" : { identifiers : [ ] , retain : true } ,
1013+ }
1014+ const wpLoadedNeedle = "do_action( 'wp_loaded' );"
10071015 const stops : Record < string , { needle : string ; after ?: boolean } > = {
10081016 "canonical-current-user" : { needle : "// Set up current user." } ,
10091017 "canonical-init" : { needle : "do_action( 'init' );" , after : true } ,
10101018 "canonical-site-status" : { needle : "// Check site status." } ,
1011- "canonical-wp-loaded" : { needle : "do_action( 'wp_loaded' );" , after : true } ,
1019+ "canonical-wp-loaded" : { needle : wpLoadedNeedle , after : true } ,
1020+ "canonical-wp-loaded-callbacks" : { needle : wpLoadedNeedle } ,
1021+ ...Object . fromEntries ( Object . keys ( wpLoadedExclusions ) . map ( ( name ) => [ name , { needle : wpLoadedNeedle } ] ) ) ,
10121022 }
10131023 const stop = stops [ phase ]
10141024 if ( ! stop ) throw new Error ( `Unknown canonical lifecycle probe phase: ${ phase } ` )
10151025
1026+ const wpLoadedProbe = phase === "canonical-wp-loaded-callbacks" || wpLoadedExclusions [ phase ]
1027+ const exclusion = wpLoadedExclusions [ phase ]
1028+ const wpLoadedStop = ! wpLoadedProbe ? "" : `function wp_codebox_canonical_wp_loaded_callback_identifier($callback) {
1029+ if (is_string($callback)) return $callback;
1030+ if ($callback instanceof Closure) return 'Closure';
1031+ if (is_array($callback) && count($callback) === 2 && is_string($callback[1])) {
1032+ $class = is_object($callback[0]) ? get_class($callback[0]) : $callback[0];
1033+ return is_string($class) ? $class . '::' . $callback[1] : 'Closure';
1034+ }
1035+ if (is_object($callback) && method_exists($callback, '__invoke')) return get_class($callback) . '::__invoke';
1036+ return 'Closure';
1037+ }
1038+ function wp_codebox_canonical_wp_loaded_inventory() {
1039+ $inventory = array();
1040+ $hook = isset($GLOBALS['wp_filter']['wp_loaded']) ? $GLOBALS['wp_filter']['wp_loaded'] : null;
1041+ if (!$hook || !isset($hook->callbacks) || !is_array($hook->callbacks)) return $inventory;
1042+ $remaining = 100;
1043+ foreach ($hook->callbacks as $priority => $callbacks) {
1044+ if (0 === $remaining) break;
1045+ $identifiers = array();
1046+ foreach ($callbacks as $registered) if (isset($registered['function'])) $identifiers[] = wp_codebox_canonical_wp_loaded_callback_identifier($registered['function']);
1047+ sort($identifiers, SORT_STRING);
1048+ $identifiers = array_slice($identifiers, 0, $remaining);
1049+ if ($identifiers) {
1050+ $inventory[(string) $priority] = $identifiers;
1051+ $remaining -= count($identifiers);
1052+ }
1053+ }
1054+ ksort($inventory, SORT_NUMERIC);
1055+ return $inventory;
1056+ }
1057+ function wp_codebox_canonical_wp_loaded_remove_snapshot($identifiers, $retain) {
1058+ $removed = array();
1059+ $hook = isset($GLOBALS['wp_filter']['wp_loaded']) ? $GLOBALS['wp_filter']['wp_loaded'] : null;
1060+ if (!$hook || !isset($hook->callbacks) || !is_array($hook->callbacks)) return $removed;
1061+ $callbacks_by_priority = $hook->callbacks;
1062+ foreach ($callbacks_by_priority as $priority => $callbacks) {
1063+ foreach ($callbacks as $registered) {
1064+ if (!isset($registered['function'])) continue;
1065+ $identifier = wp_codebox_canonical_wp_loaded_callback_identifier($registered['function']);
1066+ $matches = in_array($identifier, $identifiers, true);
1067+ if (($retain && !$matches) || (!$retain && $matches)) {
1068+ if (remove_action('wp_loaded', $registered['function'], (int) $priority)) $removed[] = $identifier;
1069+ }
1070+ }
1071+ }
1072+ sort($removed, SORT_STRING);
1073+ return $removed;
1074+ }
1075+ $inventory = wp_codebox_canonical_wp_loaded_inventory();
1076+ ${ phase === "canonical-wp-loaded-callbacks" ? `echo json_encode(array('wordpressVersion' => $wp_version, 'bootstrapPhase' => '${ phase } ', 'callbacks' => $inventory, 'memoryBytes' => memory_get_usage(true), 'peakMemoryBytes' => memory_get_peak_usage(true)));
1077+ return;` : `$removed = wp_codebox_canonical_wp_loaded_remove_snapshot(${ JSON . stringify ( exclusion ?. identifiers ?? [ ] ) } , ${ exclusion ?. retain ? "true" : "false" } );
1078+ $memory_before = memory_get_usage(true);
1079+ do_action('wp_loaded');
1080+ echo json_encode(array('wordpressVersion' => $wp_version, 'bootstrapPhase' => '${ phase } ', 'completed' => true, 'callbacks' => $inventory, 'removedCallbacks' => $removed, 'memoryBeforeBytes' => $memory_before, 'memoryBytes' => memory_get_usage(true), 'peakMemoryBytes' => memory_get_peak_usage(true)));
1081+ return;` } `
10161082 return `<?php
10171083$settings_path = '/wordpress/wp-settings.php';
10181084$settings = file_get_contents($settings_path);
@@ -1021,6 +1087,7 @@ if (substr_count($settings, $needle) !== 1) {
10211087 throw new Exception('WordPress canonical lifecycle probe needle was not uniquely found.');
10221088}
10231089$stop = <<<'PHP'
1090+ ${ wpLoadedStop }
10241091echo json_encode(array(
10251092 'wordpressVersion' => $wp_version,
10261093 'bootstrapPhase' => '${ phase } ',
0 commit comments