Es gibt einige richtig schöne deutschsprachige Beiträge, die die Befehlspalette (englisch: Command Palette) in WordPress beschreiben. Ich würde hier gerne beschreiben, wie man sie als Entwickler in eigenen Plugins verwenden kann.
Disclaimer
Dieser Beitrag spiegelt meine Erfahrungen im Umgang mit der Command Palette als Entwickler wieder. Diese habe ich in den Monaten vor diesem Beitrag sammeln dürfen. Da WordPress sich ständig weiterentwickelt, kann es in Zukunft auch an der Command Palette weitere Änderungen geben, die hier ggfs. nicht bedacht werden. Sie kann jedoch durchaus produktiv eingesetzt werden, wie man an einigen meiner eigenen Plugins sehen kann.
Worum geht es?
Hier würde ich das Wort gerne den oben bereits erwähnten Beiträgen übergeben. Hier einige Beispiel (nach Alphabet sortiert):
- https://einstieg-in-wp.de/befehlspalette/
- https://kulturbanause.de/blog/die-wordpress-befehlspalette-command-palette/
- https://www.perun.net/2023/09/14/was-ist-und-was-kann-die-wordpress-befehlspalette/
Da die Artikel teilweise schon etwas älter sind, möchte ich noch ergänzen, dass seit WordPress 6.9 die Befehlspalette überall in WordPress zur Verfügung steht – nicht nur im Site Editor. Das ist eine der oben ebenfalls schon angesprichenen Änderungen, die es so im Laufe der Zeit eben gibt. Damit eröffnen sich für Entwickler wie Anwender jedoch gleichzeitig völlig neue Möglichkeiten in der Bedienung von WordPress.
Fallbeispiele
Ich habe die Befehlspalette bereits in einigen meiner WordPress Plugins eingebaut. Ihr findet sie in:
- Externe Dateien in der Mediathek
- um verfügbare Dienste zum Beziehen externer Dateien schnell aufzurufen
- um gespeicherte externe Quellen direkt zu öffnen
- Personio Integration Light
- um den Import von Stellen anzustoßen
- um schnell importiere offene Stellen zu öffnen
- und eingegangene Bewerbungen zu finden (nur Pro)
Grenzen
Bevor man beginnt eigene Ergänzungen in der Befehlspalette zu entwickeln, sollte man sich genau überlegen, was diese machen soll und welchen Mehrwert sie für die Anwender bieten kann. Sinnvoll sind grundsätzlich alle Themen, die dem Anwender in WordPress die Arbeit erleichtern.
Einen eigenen Befehl ergänzen
Die offizielle Dokumentation dazu ist übrigens hier zu finden: https://wordpress.org/documentation/article/site-editor-command-palette/ – allerdings, wie ich merkte, nicht immer auf dem aktuellsten Stand. Daher hier die Beschreibung wie ich zu Anfang 2026 vorgegangen bin.
Zielsetzung
Wir möchten die Inhalte eines Custom Post Type über die Befehlspalette auffindbar machen. Ebenso soll es ein Kommando geben, um schnell eine neuen Beitrag in diesem Post Type zu ergänzen.
Voraussetzungen
Du benötigst hierfür eine Entwicklungsumgebung mit npm. Dieses braucht man um das Script zu kompilieren und damit auch einsatzfähig zu machen. Und natürlich WordPress in der aktuellsten Version, um dein Plugin zu testen.
Plugin anlegen
Wenn noch nicht geschehen, richten wir uns zunächst unser Demo-Plugin ein. Ich nenne es „Command Palette Demo“ und gehe folgende Schritte:
- In
/wp-content/plugins/ein neues Verzeichnis namens „command-palette-demo“ anlegen. - Darin eine Datei
command-palette-demo.phpmit dem folgenden Inhalt anlegen:
<?php
/**
* Plugin Name: Command Palette Demo
* Description: This plugin demonstrate the usage of the command palette.
* Requires at least: 6.9
* Requires PHP: 8.1
* Version: 1.0.0
* Author: Thomas Zwirner
* Author URI: https://www.thomaszwirner.de
* License: GPL-2.0-or-later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: command-palette-demo
*
* @package command-palette-demo
*/
/**
* Register our own post type for demo purposes.
*
* @return void
*/
function cpd_register_post_type(): void {
// set arguments for our own cpt.
$args = array(
'label' => __( 'Command Palette Demo', 'command-palette-demo' ),
'labels' => array(),
'supports' => array( 'title', 'editor' ),
'public' => true,
'show_in_rest' => true
);
register_post_type( 'cpd_demo', $args );
}
add_action( 'init', 'cpd_register_post_type' );
/**
* Refresh the permalinks on plugin activation.
*/
register_activation_hook( __FILE__, static function() {
flush_rewrite_rules();
} );
Zwischenstand
- Wir haben ein Demo-Plugin, welches nach Aktivierung einen Custom Post Typ einrichtet.
- Die Einträge des Custom Post Types sind in der REST API zu sehen. Das wird später für die Befehlspalette wichtig.
- Beim Aktivieren des Plugins werden die WordPress-eigenen Permalinks neu erzeugt.
- Dieser Custom Post Type ist im Backend bereits zu sehen.
Inhalte anlegen
Als nächstes lege ich 2-3 Datensätze in dem Custom Post Type an. Eigentlich ist es völlig egal, welchen Inhalt sie haben. Wir wollen sie aber später über die Befehlspalette suchen können. Daher merke ich mir sehr gut, welchen Titel sie haben um ihn später zum Suchen zu verwenden.
Endlich ein Script schreiben
Genug der Vorbereitungen. Jetzt gehts an das Script für die Ergänzung an der Command Palette:
- Ich erstelle innerhalb des Plugin-Verzeichnisses ein Verzeichnis
src. - In diesem erstelle ich eine Datei namens
index.js. Die Datei bleibt erstmal leer. Der Dateiname ist euch überlassen – wenn er anders lautet, müsste er jedoch auch an anderen Stellen wie in der folgendenpackage.jsonangepasst werden. - Im Hauptverzeichnis vom Plugin ergänze ich eine Datei namens
package.json. Diese Datei bekommt den folgenden Inhalt.
{
"name": "@command-palette-demo/command-palette-demo",
"version": "1.0.0",
"description": "Provides command palette for Command Palette Demo.",
"author": "Thomas Zwirner",
"license": "GPL-2.0-or-later",
"main": "index.js",
"scripts": {
"build": "wp-scripts build",
"start": "wp-scripts start"
},
"dependencies": {
"@wordpress/icons": "^11.3.0",
"@wordpress/scripts": "^31.1.0"
}}
Was macht diese Datei? Sie stellt für npm die Konfiguration bereit, um aus dem Script unter src/index.js ein ausführbares Script zu erzeugen, was dann standardmäßig, da nicht anders angegeben, im Verzeichnis build gespeichert wird.
Jetzt ergänzen wir den folgenden Inhalt in der Datei src/index.js. Ich erkläre die einzelnen Abschnitte:
/**
* Embed requirements.
*/
import { store as commandsStore } from '@wordpress/commands';
import { dispatch } from '@wordpress/data';
import { useSelect } from '@wordpress/data';
import { useMemo, useEffect } from "@wordpress/element";
import { addQueryArgs } from '@wordpress/url';
import { post } from '@wordpress/icons';
Das sind die für das Script erforderlichen Dateien. npm wird sich drum kümmern, diese in das zu erzeugende Script einzubinden.
Weiter gehts:
/**
* Initiate the custom command to search for services.
*/
dispatch( commandsStore ).registerCommandLoader( {
name: 'command-palette-demo/posts',
hook: useDemoPostsInCommandPalette,
} );
Dieser Funktionsaufruf definiert, dass die Befehlspalette erweitert werden soll. Die Ergänzung hat den internen Namen command-palette-demo/posts und ruft die Funktion useDemoPostsInCommandPalette() auf. Der interne Name sollte mit dem Plugin-Slug beginnen und nach dem Slash die Aufgabe beschreiben. In dem Fall geht es um das Auslesen der Beiträge (Posts) unseres Post Types.
Die Funktion useDemoPostsInCommandPalette() wird nun etwas umfangreicher, weshalb ich sie einzeln erkläre. Der Rahmen sieht so aus:
function useDemoPostsInCommandPalette( { search } ) {
}
Die einzige Variable search enthält den Suchbegriff, der vom Nutzer in der Befehlspalette eingegeben wird. Das können einzelne Zeichen oder auch ganze Sätze sein.
Hiermit rufen wir nun die Datensätze mit dem angegebenen Suchbegriff über die REST API von WordPress ab. Diese werden in der Variable records gespeichert:
// Retrieve the pages for the "search" term.
const { records, isLoading } = useSelect(
(select) => {
const { getEntityRecords } = select(coreStore);
const query = {
search: !!search ? search : undefined,
per_page: 10,
orderby: search ? "relevance" : "date",
};
return {
records: getEntityRecords("postType", "cpd_demo", query),
isLoading: !select(coreStore).hasFinishedResolution(
"getEntityRecords",
"postType",
"page",
query
),
};
},
[search]
);
Anschließend bauen wir aus diesen Datensätzen das Ergebnis für die Befehlspalette zusammen:
/**
* Create the commands.
*/
const commands = useMemo(() => {
return (records ?? []).slice(0, 10).map((record) => {
return {
name: record.title?.rendered + " " + record.id,
label: record.title?.rendered
? record.title?.rendered
: __("(no title)"),
icon: post,
category: 'view',
callback: ({ close }) => {
const args = {
action: 'edit',
post: record.id
};
document.location = addQueryArgs("post.php", args);
close();
},
};
});
}, [records, history]);
Dieser längere Code realisiert die Ausgabe der records in der Befehlspalette. Diese werden hier einzeln durchgegangen und die von der Befehlspalette angeforderten Daten pro Eintrag zusammengesetzt. Das sind im einzelnen:
- Ein eindeutiger Name.
- Als
labeldie anzuzeigende Bezeichnung. - Als
iconein Post-Icon von WordPress. - Als Kategorie wird ‚view“ gewählt, da es um die Anzeige von Datensätzen geht.
- Und als callback() wird das Event definiert was beim Anklicken des Eintrags in der Befehlspalette durch den Anwender ausgeführt werden soll. Hier sorgen wir dafür, dass er auf die Bearbeitungsseite des Beitrags kommt. Die Zusammensetzung der URL mit
addQueryArgs()ist ähnlich dem add_query_args() in WordPress.
return {
commands
};
Abschließend sorgen wir noch dafür, dass das Kommando auch zurückgegeben wird an die Befehlspalette.
Zwischenstand
Damit haben wir das Script erstellt sowie die nötigen Bedingungen es zu kompilieren.
Kompilieren
Führe nun an der Kommandozeile folgendes aus:
npm i
npm run build
Ersteres ist einmalig notwendig um alle Quellen zu holen.
Letzteres musst du ab sofort immer dann ausführen, wenn du eine Änderung am Script vornimmst. Alternativ kannst du zur Entwicklung auch npm start verwenden, dann wird das Script für dich live nach jeder Änderung kompiliert.
Ausführbar machen
Damit wir das Script überhaupt im Backend laden, wird es nun noch eingebunden. Dazu nutzen wir folgenden Code:
/**
* Add scripts to enable the command palette addition to the admin area.
*
* @return void
*/
function cpd_enqueue_scripts(): void {
// get path for the asset script.
$script_asset_path = trailingslashit( plugin_dir_path( __FILE__ ) ) . 'build/index.asset.php';
// bail if the asset script does not exist.
if ( ! file_exists( $script_asset_path ) ) {
return;
}
// embed script.
$script_asset = require $script_asset_path;
wp_enqueue_script(
'command-palette-demo',
trailingslashit( plugin_dir_url( __FILE__ ) ) . 'build/index.js',
$script_asset['dependencies'],
$script_asset['version'],
true
);
}
add_action( 'admin_enqueue_scripts', 'cpd_enqueue_scripts' );
Testen
Solltest du das Plugin noch nicht aktiviert haben, mach das jetzt. Ergänze anschließend 2-3 Beiträge in der Custom Post Type „Command Palette Demo“ um danach suchen zu können.
Sobald du das hast und dich weiterhin irgendwo im WordPress Backend befindest, drücke Strg + K gleichzeitig – die Befehlspalette öffnet sich. Gib hier nun ein Wort aus einem der angelegten Beiträge ein. Es sollte im Idealfall so aussehen:

Geht nicht?
Prüfe folgende Dinge:
- Ist das Plugin wirklich aktiviert?
- Enthält der PHP-Code vom Plugin die Einbindung der Datei
build/index.js? - Hat npm die Kompilierung vollständig vorgenommen?
- Hast du Fehler in der JavaScript-Konsole in deinem Browser?
Eines davon wird es sein. Prüfe anhand dessen die oben beschrieben Anleitung nochmals gegen deine Implementierung.
Eine Aktion ausführen
Die Befehlspalette kann ebenso verwendet werden, um schnell eine konkrete Aufgabe auszuführen. Um das in deinem Script zu verwenden, musst du lediglich den o.g. Hook verwenden, in diesem Name und Funktionsname für den Hook anpassen und dann folgendes Script einfügen:
/**
* Define our custom action.
*
* @returns {{commands: *}}
*/
function addCommandInCommandPalette() {
const commands = useMemo( () => {
return [
{
name: 'command-palette-demo/new',
label: __( 'New Demo Post', 'command-palette-demo' ),
icon: personioIcon,
callback: ( { close } ) => {
close();
const args = {
post_type: 'cpd_demo',
};
document.location = addQueryArgs("post-new.php", args);
},
},
];
}, [] );
return { commands };
}
Statt der Weiterleitung, kann hier auch jegliches andere JavaScript-basierte Kommando ausgeführt werden. Diese können wiederum weitere Requests an den Server schicken um Aufgaben zu erledigen.
Fazit
Ich habe hier gezeigt, wie man selbst die Befehlspalette erweitern kann. Mit welchem Möglichkeiten, ist ganz eurer Fantasie überlassen.
Der Quellcode aus dem Artikel ist in diesem GitHub Repository zu finden: https://github.com/threadi/command-palette-demo