From c4020d7c044a12a8087bb85198a21dcceedc4522 Mon Sep 17 00:00:00 2001 From: David Stone Date: Mon, 30 Mar 2026 14:46:07 -0600 Subject: [PATCH] fix(dashboard): enqueue activity-stream script during admin_enqueue_scripts The activity-stream.js was enqueued inside the view template during widget rendering (meta_box output), which fires after admin_enqueue_scripts. WordPress cannot properly resolve the dependency chain for scripts enqueued that late, so wu-functions (which defines window.wu_moment) was not loaded before activity-stream.js executed, causing 'ReferenceError: wu_moment is not defined' and leaving the Activity Stream widget stuck on 'Loading...' permanently. Move the wp_enqueue_script call to Dashboard_Widgets::enqueue_scripts() where it runs during admin_enqueue_scripts, and add moment as a declared dependency of wu-functions since functions.js uses moment.tz/moment.utc in wu_moment. --- inc/class-dashboard-widgets.php | 11 ++++++ inc/class-scripts.php | 2 +- tests/WP_Ultimo/Dashboard_Widgets_Test.php | 39 +++++++++++++++++++++ views/dashboard-widgets/activity-stream.php | 5 ++- 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/inc/class-dashboard-widgets.php b/inc/class-dashboard-widgets.php index bd0496953..703b2cc0c 100644 --- a/inc/class-dashboard-widgets.php +++ b/inc/class-dashboard-widgets.php @@ -85,6 +85,17 @@ public function enqueue_scripts(): void { * we must enqueue wu-functions explicitly here. */ wp_enqueue_script('wu-functions'); + + /* + * Enqueue the activity-stream script here — during admin_enqueue_scripts — + * so WordPress resolves the full dependency chain (wu-functions, moment, etc.) + * before the script runs. Previously this was enqueued inside the view + * template during widget rendering, which fires after admin_enqueue_scripts + * and caused wu_moment to be undefined. + */ + wp_enqueue_script('wu-activity-stream', wu_get_asset('activity-stream.js', 'js'), ['wu-vue', 'wu-functions', 'moment'], wu_get_version(), true); + + wp_add_inline_script('wu-activity-stream', 'var wu_activity_stream_nonce = "' . esc_js(wp_create_nonce('wu_activity_stream')) . '";', 'before'); } /** diff --git a/inc/class-scripts.php b/inc/class-scripts.php index 5a7feeb46..9d5d980ca 100644 --- a/inc/class-scripts.php +++ b/inc/class-scripts.php @@ -190,7 +190,7 @@ public function register_default_scripts(): void { /* * Adds General Functions */ - $this->register_script('wu-functions', wu_get_asset('functions.js', 'js'), ['jquery-core', 'wu-tiptip', 'wu-flatpicker', 'wu-block-ui', 'wu-accounting', 'clipboard', 'wp-hooks']); + $this->register_script('wu-functions', wu_get_asset('functions.js', 'js'), ['jquery-core', 'moment', 'wu-tiptip', 'wu-flatpicker', 'wu-block-ui', 'wu-accounting', 'clipboard', 'wp-hooks']); wp_localize_script( 'wu-functions', diff --git a/tests/WP_Ultimo/Dashboard_Widgets_Test.php b/tests/WP_Ultimo/Dashboard_Widgets_Test.php index 96e9aafdb..14bd7da55 100644 --- a/tests/WP_Ultimo/Dashboard_Widgets_Test.php +++ b/tests/WP_Ultimo/Dashboard_Widgets_Test.php @@ -113,6 +113,45 @@ public function test_enqueue_scripts_skips_non_index_page(): void { $pagenow = $original; } + /** + * Test enqueue_scripts enqueues activity-stream with correct deps on index.php. + */ + public function test_enqueue_scripts_enqueues_activity_stream_on_index(): void { + + global $pagenow, $wp_scripts; + + $original = $pagenow; + $original_queue = isset($wp_scripts) ? $wp_scripts->queue : []; + $pagenow = 'index.php'; + + if (isset($wp_scripts)) { + $wp_scripts->queue = []; + $wp_scripts->done = []; + } + + // Ensure wu-functions is registered so the dependency chain resolves. + \WP_Ultimo\Scripts::get_instance()->register_default_scripts(); + + $instance = $this->get_instance(); + $instance->enqueue_scripts(); + + $this->assertTrue( + wp_script_is('wu-activity-stream', 'enqueued'), + 'wu-activity-stream should be enqueued on index.php' + ); + + // Verify wu-functions and moment are declared dependencies. + $script = $wp_scripts->registered['wu-activity-stream'] ?? null; + $this->assertNotNull($script, 'wu-activity-stream should be registered'); + $this->assertContains('wu-functions', $script->deps); + $this->assertContains('moment', $script->deps); + + if (isset($wp_scripts)) { + $wp_scripts->queue = $original_queue; + } + $pagenow = $original; + } + /** * Test get_registered_dashboard_widgets returns array. * diff --git a/views/dashboard-widgets/activity-stream.php b/views/dashboard-widgets/activity-stream.php index 072d03ee0..a4d73878a 100644 --- a/views/dashboard-widgets/activity-stream.php +++ b/views/dashboard-widgets/activity-stream.php @@ -120,7 +120,6 @@ class='wu-feed-pagination wu-m-0 wu-flex wu-justify-between'>