I want a sidebar panel in the post editor where a user can pick an assignee and an editor for a post. The post will be populated by a list of every user on the site. When the page loads, I want the current value to be highlighted.
So far I have this as my component (not pictured is the functions.php file where I register the custom fields):
/**
* React.
*/
import React, { useState, useEffect } from 'react';
/**
* WordPress dependencies.
*/
import { useSelect, useDispatch } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { store as editorStore } from '@wordpress/editor';
import { PluginDocumentSettingPanel } from '@wordpress/edit-post';
import { SelectControl, PanelRow, Button, Notice, Spinner } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
/**
* Assignee and Editor Settings Panel.
*/
export default function AssigneeAndEditorSettingsPanel(): JSX.Element {
// Get post type, post ID, and meta fields.
const { postType, postId, meta } = useSelect((select) => {
return {
postType: select(editorStore).getCurrentPostType(),
postId: select(editorStore).getCurrentPostId(),
meta: select(editorStore).getEditedPostAttribute('meta'),
};
}, []);
// Local state for selected users.
const [selectedAssignee, setSelectedAssignee] = useState(meta?.assignee || '');
const [selectedEditor, setSelectedEditor] = useState(meta?.editor || '');
const [loading, setLoading] = useState(false);
const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
// Update state when meta values change.
useEffect(() => {
setSelectedAssignee(meta?.assignee || '');
setSelectedEditor(meta?.editor || '');
}, [meta]);
// Get all users for dropdown.
const users = useSelect((select) => {
return select(coreStore).getEntityRecords('root', 'user', { per_page: -1 }) || [];
}, []);
const { editEntityRecord, saveEntityRecord } = useDispatch(coreStore);
const saveAssigneeAndEditor = async () => {
setLoading(true);
setMessage(null);
try {
console.log('Saving post meta for post ID:', postId);
console.log('Post type:', postType);
console.log('New meta:', { assignee: selectedAssignee, editor: selectedEditor });
// Update entity record
editEntityRecord('postType', postType, postId, {
meta: {
assignee: selectedAssignee || '',
editor: selectedEditor || '',
},
});
// Save and check response
const response = await saveEntityRecord('postType', postType, postId);
console.log('Save response:', response);
if (response) {
setMessage({ type: 'success', text: __('Changes saved.', 'text-domain') });
} else {
throw new Error('No response returned.');
}
} catch (error) {
console.error('Save Error:', error);
setMessage({ type: 'error', text: __('Failed to save changes.', 'text-domain') });
} finally {
setLoading(false);
}
};
return (
<PluginDocumentSettingPanel
name="assignee-and-editor-settings-panel"
title={__('Assignee & Editor', 'text-domain')}
className="assignee-and-editor-settings-panel"
>
<PanelRow>
<SelectControl
label={__('Assignee', 'text-domain')}
value={selectedAssignee}
options={[
{ label: __('Select an Assignee', 'text-domain'), value: '' },
...users.map((user) => ({ label: user.name, value: user.id })),
]}
onChange={setSelectedAssignee} // Only updates local state
/>
</PanelRow>
<PanelRow>
<SelectControl
label={__('Editor', 'text-domain')}
value={selectedEditor}
options={[
{ label: __('Select an Editor', 'text-domain'), value: '' },
...users.map((user) => ({ label: user.name, value: user.id })),
]}
onChange={setSelectedEditor} // Only updates local state
/>
</PanelRow>
{/* Save Button */}
<PanelRow>
<Button isPrimary onClick={saveAssigneeAndEditor} disabled={loading}>
{loading ? <Spinner /> : __('Save Changes', 'text-domain')}
</Button>
</PanelRow>
{/* Success/Error Notice */}
{message && (
<Notice status={message.type} onRemove={() => setMessage(null)}>
{message.text}
</Notice>
)}
</PluginDocumentSettingPanel>
);
}
The issue is that I need to hit the "update" button on top to write these to the db. Is there a way to make them write to custom fields when I hit the button?