Skip to content

Add command palette registration APIs and sync functionality#5

Merged
AllTerrainDeveloper merged 2 commits into
trunkfrom
fix/command-palette-live-refresh
Apr 23, 2026
Merged

Add command palette registration APIs and sync functionality#5
AllTerrainDeveloper merged 2 commits into
trunkfrom
fix/command-palette-live-refresh

Conversation

@AllTerrainDeveloper

@AllTerrainDeveloper AllTerrainDeveloper commented Apr 23, 2026

Copy link
Copy Markdown
Collaborator

Summary

Newly-installed or activated plugins that register slash-commands via wp.desktop.registerCommand() didn't appear in the palette until a full page reload — the plugin's JS was never enqueued into the currently-running shell page, so nothing called registerCommand until F5.

Fix it the same way widgets and wallpapers solve the equivalent problem: server-declare the plugin's command script in PHP, extend the wp-desktop-plugins-changed payload with the resolved URL, and have a new src/commands/server-sync.ts module dynamically inject the script on activation. Live-unregister the plugin's commands on deactivation.

New public API

wp_desktop_register_command_script( 'my-plugin-commands' );

One line of PHP. The plugin keeps its command definitions in JavaScript where the run function already lives. On mid-session install / activate, the shell injects the script and the new commands appear in the palette with no reload. On deactivate, commands whose owner matches the departing script handle are unregistered live.

Minimal working plugin (/echo)

Drop these two files into wp-content/plugins/my-echo/ and activate.

my-echo.php

<?php                                                                                                                                                                                                                                                                                                                                                                                                                     
  /**                                                       
   * Plugin Name: My Echo Command
   */                                                                                                                                                                                                                                                                                                                                                                                                                       
   
  defined( 'ABSPATH' ) || exit;                                                                                                                                                                                                                                                                                                                                                                                             
                                                            
  add_action( 'admin_enqueue_scripts', function () {                                                                                                                                                                                                                                                                                                                                                                        
      wp_register_script(
          'my-echo-commands',                                                                                                                                                                                                                                                                                                                                                                                               
          plugins_url( 'echo.js', __FILE__ ),               
          array(),                                                                                                                                                                                                                                                                                                                                                                                                          
          '1.0.0',
          true                                                                                                                                                                                                                                                                                                                                                                                                              
      );                                                    
      wp_enqueue_script( 'my-echo-commands' );
  } );                                                                                                                                                                                                                                                                                                                                                                                                                      
   
  add_action( 'init', function () {                                                                                                                                                                                                                                                                                                                                                                                         
      if ( function_exists( 'wp_desktop_register_command_script' ) ) {
          wp_desktop_register_command_script( 'my-echo-commands' );                                                                                                                                                                                                                                                                                                                                                         
      }
  } );                                                                                                                                                                                                   

echo.js

  ( function () {
      function register() {
          window.wp.desktop.registerCommand( {
              slug:  'echo',                                                                                                                                                                                                                                                                                                                                                                                                
              label: 'Echo',
              icon:  'dashicons-format-chat',                                                                                                                                                                                                                                                                                                                                                                               
              owner: 'my-echo-commands', // enables live-unregister on deactivate                                                                                                                                                                                                                                                                                                                                           
              run:   ( args ) => args.trim() || 'Usage: /echo [text]',                                                                                                                                                                                                                                                                                                                                                      
          } );                                                                                                                                                                                                                                                                                                                                                                                                              
      }                                                                                                                                                                                                                                                                                                                                                                                                                     
      if ( window.wp && window.wp.desktop && window.wp.desktop.registerCommand ) {
          register();                                                                                                                                                                                                                                                                                                                                                                                                       
      } else {
          document.addEventListener( 'wp-desktop-init', register, { once: true } );                                                                                                                                                                                                                                                                                                                                         
      }                                                     
  } )();

Open the palette, type /echo hello → replies with hello.

Changes

PHP

  • includes/commands.php — wp_desktop_register_command_script(), internal registry, payload builder.
  • includes/helpers.php — adds serverCommandScripts (and serverCommands) to wpdm_build_menu_payload(). REST /menu endpoint inherits them automatically.
  • includes/render.php — unpacks the new keys into wp_desktop_shell_config.
  • wp-desktop-mode.php — requires the new include.

TypeScript

  • src/commands/server-sync.ts — new sync module, mirrors wallpapers/server-sync.ts. Loads opted-in scripts via loadVendorScript, tracks loaded handles, unregisters owner-tagged commands on deactivation.
  • src/commands.ts — optional owner field on DesktopCommand.
  • src/types.ts — DesktopCommandScriptServerEntry, new payload fields on DesktopConfig.
  • src/desktop.ts — creates the sync at init(), wires it into applyPayload() and bindMenuRefresh().

Docs

  • docs/hooks-reference.md — Stable entries for the new PHP function and its registration action.
  • docs/javascript-reference.md — new section on live-refresh behavior and the owner field.

Repo-level CLAUDE.md — captures the plugins-changed live-refresh architecture so future changes don't re-derive it.

Tests

  • Vitest — 5 new cases in tests/vitest/commands-server-sync.test.ts (script injection, idempotency, deactivation unregister, empty-URL skip). Full suite 364/364 green.
  • PHPUnit — 7 new cases in tests/phpunit/tests/commands.php. Group desktop-mode.
  • tsc --noEmit clean.

Plugin migration

Zero work required for existing plugins — they keep their current F5 behavior. Plugins that want live-refresh add the one-line PHP call shown above and (optionally) set owner on their registerCommand calls to get live-unregister on deactivate.

Test plan

  • Drop in the minimal /echo plugin above, activate from plugins.php → type / in the palette, Echo appears, /echo hi → hi. No reload.
  • Deactivate the plugin → /echo disappears from the palette. No reload.
  • npm test → 364 passed.
  • npm run test:php → new commands.php group green.
  • npx tsc --noEmit → no errors.

- Introduced `wp_desktop_register_command_script()` to register command-palette script handles, allowing live command registration without page reloads.
- Added `wp_register_desktop_command()` for server-side command metadata registration, enabling future pre-registration shims.
- Implemented server-side command sync in `src/commands/server-sync.ts`, handling script injection and command unregistration on plugin deactivation.
- Updated JavaScript reference documentation to include new command registration methods and their usage.
- Enhanced PHP documentation for command registration functions.
- Created unit tests for command registration and sync functionalities to ensure reliability.
- Updated the main plugin file to include the new commands module.
@AllTerrainDeveloper AllTerrainDeveloper merged commit 10a59ae into trunk Apr 23, 2026
1 of 3 checks passed
@AllTerrainDeveloper AllTerrainDeveloper deleted the fix/command-palette-live-refresh branch April 23, 2026 11:13
AllTerrainDeveloper added a commit that referenced this pull request May 3, 2026
Two CI breakages on the routines PR:

1. **`test_if_branch_routes_correctly` failed** with "Undefined
   array key 'branch'" at log index 0. The executor was pushing
   the `if`-step entry to the steps_log AFTER walking its
   children, so the first entry in the log was a child step
   (no `branch` key), not the if itself.

   Fix: push the `if` entry FIRST with a `ms: 0` placeholder,
   capture its index, then patch the total `ms` (children
   included) by indexing back into the log after the recursive
   walk finishes. Result: log reads chronologically — "if went
   to then, then set_var ran" instead of "set_var ran somewhere,
   then we found out it was the then branch of an if".

2. **CI output polluted** with stray `[wpdm-routine #5] INFO:
   hi Daniel` lines from the `log` step's tests. The handler
   was calling `error_log` unconditionally; under PHPUnit the
   write goes to stderr and litters the run's output log.

   Fix: same pattern the `wait` step already uses to skip
   `sleep` — short-circuit the actual error_log call when
   `WP_TESTS_DOMAIN` (or `WP_RUN_CORE_TESTS`) is defined. The
   step still returns its payload so the routine's per-step log
   captures the message; we just don't double-write to the PHP
   log where no human will read it during a CI run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@claude claude Bot mentioned this pull request May 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant