The Sidebar Render API uses filter hooks similar to the Dashboard Cards API, allowing plugins to register components that will be rendered in specific locations within the sidebar. Components can be written in either Vue.js or React, with automatic integration via veaury.
uixpress/sidebar/render/premenu - Components rendered before the menu itemsuixpress/sidebar/render/postmenu - Components rendered after the menu items, before user detailsFilter Hook - Modifies the components array
addFilter('uixpress/sidebar/render/premenu', (components) => {
// Modify components array
return components;
}, priority);
addFilter('uixpress/sidebar/render/postmenu', (components) => {
// Modify components array
return components;
}, priority);
components (Array): The current array of component objectspriority (Number, optional): Priority for the filter (default: 10). Lower numbers run first.Returns an array of component objects.
Each component must be an object with the following structure:
{
metadata: {
id: string, // Unique identifier (required)
language: string, // 'vue' or 'react' (optional, default: 'vue')
className: string, // CSS classes to apply (optional)
requires_capabilities: Array, // User capabilities required (optional)
},
component: Component // Vue or React component (required)
}
id (string, required)
my-plugin/premenu-widget)language (string, optional)
'vue' or 'react''vue'className (string, optional)
requires_capabilities (Array, optional)
['manage_options', 'edit_posts']component (Component, required)
import { addFilter } from '@/assets/js/functions/HooksSystem.js';
// Or use window.uixpress.addFilter if outside Vue app
import MyPreMenuComponent from './my-premenu-component.vue';
addFilter('uixpress/sidebar/render/premenu', (components) => {
return [
...components,
{
metadata: {
id: 'my-plugin/premenu-widget',
language: 'vue',
className: 'p-4',
requires_capabilities: ['manage_options'],
},
component: MyPreMenuComponent,
},
];
});
import { addFilter } from '@/assets/js/functions/HooksSystem.js';
import MyPostMenuComponent from './MyPostMenuComponent.jsx';
addFilter('uixpress/sidebar/render/postmenu', (components) => {
return [
...components,
{
metadata: {
id: 'my-plugin/postmenu-widget',
language: 'react',
className: 'border-t border-zinc-200 dark:border-zinc-800 pt-4',
},
component: MyPostMenuComponent,
},
];
});
<script setup>
import { defineProps } from 'vue';
import { useAppStore } from '@/store/app/app.js';
const props = defineProps({
appData: Object,
id: String,
className: String,
});
const appStore = useAppStore();
</script>
<template>
<div :class="className" class="p-4 bg-zinc-50 dark:bg-zinc-800 rounded-lg">
<h3 class="text-sm font-semibold text-zinc-900 dark:text-zinc-100 mb-2">
My Custom Widget
</h3>
<p class="text-xs text-zinc-600 dark:text-zinc-400">
This component appears before the menu items.
</p>
</div>
</template>
import React from 'react';
/**
* Post-menu React component
* @param {Object} props - Component props
* @param {Object} props.appData - App store instance
* @param {string} props.id - Component ID
* @param {string} props.className - CSS classes
*/
const MyPostMenuComponent = ({ appData, id, className }) => {
return (
<div className={`p-4 bg-zinc-50 dark:bg-zinc-800 rounded-lg ${className || ''}`}>
<h3 className="text-sm font-semibold text-zinc-900 dark:text-zinc-100 mb-2">
My Custom Widget
</h3>
<p className="text-xs text-zinc-600 dark:text-zinc-400">
This component appears after the menu items.
</p>
</div>
);
};
export default MyPostMenuComponent;
import { addFilter } from '@/assets/js/functions/HooksSystem.js';
addFilter('uixpress/sidebar/render/premenu', (components) => {
const newComponents = [...components];
// Only add component if user has specific capability
if (window.uixpress?.state?.currentUser?.allcaps?.manage_options) {
newComponents.push({
metadata: {
id: 'my-plugin/admin-widget',
language: 'vue',
requires_capabilities: ['manage_options'],
},
component: AdminOnlyComponent,
});
}
return newComponents;
});
import { addFilter } from '@/assets/js/functions/HooksSystem.js';
// High priority - runs first, adds component at the beginning
addFilter(
'uixpress/sidebar/render/premenu',
(components) => {
return [
{
metadata: {
id: 'my-plugin/important-widget',
language: 'vue',
},
component: ImportantComponent,
},
...components,
];
},
5 // Low priority number = runs first
);
// Low priority - runs last, adds component at the end
addFilter(
'uixpress/sidebar/render/premenu',
(components) => {
return [
...components,
{
metadata: {
id: 'my-plugin/less-important-widget',
language: 'vue',
},
component: LessImportantComponent,
},
];
},
20 // High priority number = runs last
);
Components receive the following props:
appData (Object): The app store instance (Pinia store)id (String): Component ID from metadataclassName (String): CSS classes from metadataappData (Object): The app store instance (Pinia store)id (String): Component ID from metadataclassName (String): CSS classes from metadataThe sidebar component dispatches a custom event when it's ready for plugin registration:
document.addEventListener('uixpress/sidebar/ready', () => {
// Sidebar component is ready, safe to register components
addFilter('uixpress/sidebar/render/premenu', (components) => {
// Register your components
return components;
});
});
Components registered via uixpress/sidebar/render/premenu are rendered:
Components registered via uixpress/sidebar/render/postmenu are rendered:
Always prefix your component IDs with your plugin/theme name:
{
metadata: {
id: 'my-plugin/my-component', // Good
// Not: 'my-component' // Bad - could conflict
}
}
Follow the design system:
Check user capabilities before rendering sensitive content:
{
metadata: {
requires_capabilities: ['manage_options'], // Only admins see this
}
}
Sidebar components should be lightweight and fast-loading:
If supporting both frameworks:
If you're building a WordPress plugin, you can enqueue JavaScript that registers components:
add_action('admin_enqueue_scripts', function() {
wp_enqueue_script(
'my-plugin-sidebar-components',
plugin_dir_url(__FILE__) . 'assets/sidebar-components.js',
['uixpress-app'], // Depend on uiXpress app
'1.0.0',
true
);
});
Then in your JavaScript file:
// Wait for sidebar to be ready
document.addEventListener('uixpress/sidebar/ready', () => {
if (window.uixpress?.addFilter) {
window.uixpress.addFilter('uixpress/sidebar/render/premenu', (components) => {
return [
...components,
{
metadata: {
id: 'my-plugin/my-widget',
language: 'vue',
requires_capabilities: ['manage_options'],
},
component: MyComponent, // Imported or defined elsewhere
},
];
});
}
});
addFilter correctlyuixpress/sidebar/ready eventmetadata.language is set to 'react'appData, id, className (camelCase)app-data, id, className (kebab-case)Name: uixpress/sidebar/render/premenu
Type: Filter
Parameters:
components (Array): Current components arrayReturns: Array of component objects
Priority: Default 10 (lower runs first)
Name: uixpress/sidebar/render/postmenu
Type: Filter
Parameters:
components (Array): Current components arrayReturns: Array of component objects
Priority: Default 10 (lower runs first)
Name: uixpress/sidebar/ready
Type: CustomEvent
When: Dispatched when sidebar component is mounted and ready for plugin registration
Usage: Listen for this event before registering filters