From 5215215e9ccae4c6bff6b3e105a5cf7b13a42fcf Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Thu, 17 Apr 2025 16:02:04 +0200 Subject: [PATCH 01/33] First attempt at adding command palette support --- assets/src/js/acf-command-palette.js | 47 ++++++++++++++++++++++++++++ includes/assets.php | 13 ++++++++ secure-custom-fields.php | 32 +++++++++++++++++++ webpack.config.js | 1 + 4 files changed, 93 insertions(+) create mode 100644 assets/src/js/acf-command-palette.js diff --git a/assets/src/js/acf-command-palette.js b/assets/src/js/acf-command-palette.js new file mode 100644 index 00000000..50bc3824 --- /dev/null +++ b/assets/src/js/acf-command-palette.js @@ -0,0 +1,47 @@ +/** + * SCF Command Palette integration + * + * Uses WordPress Commands API to add Secure Custom Fields commands to the WordPress command palette. + */ + +// Register commands when WordPress is ready +wp.domReady(() => { + // Make sure required WordPress dependencies are available + if (!wp.data || !wp.data.dispatch || !wp.data.dispatch('core/commands')) { + console.warn('SCF Command Palette: WordPress Commands API not available'); + return; + } + + // Access the WordPress i18n functions + const { __ } = wp.i18n; + + // Get the commands store + const commandStore = wp.data.dispatch('core/commands'); + + // Command definitions for SCF admin pages + const commands = [ + { name: 'field-groups', label: __('Field Groups', 'secure-custom-fields'), url: 'edit.php?post_type=acf-field-group' }, + { name: 'new-field-group', label: __('Create New Field Group', 'secure-custom-fields'), url: 'post-new.php?post_type=acf-field-group' }, + { name: 'post-types', label: __('Post Types', 'secure-custom-fields'), url: 'admin.php?page=acf-post-types' }, + { name: 'new-post-type', label: __('Create New Post Type', 'secure-custom-fields'), url: 'admin.php?page=acf-post-type' }, + { name: 'taxonomies', label: __('Taxonomies', 'secure-custom-fields'), url: 'admin.php?page=acf-taxonomies' }, + { name: 'new-taxonomy', label: __('Create New Taxonomy', 'secure-custom-fields'), url: 'admin.php?page=acf-taxonomy' }, + { name: 'options-pages', label: __('Options Pages', 'secure-custom-fields'), url: 'admin.php?page=acf-options-pages' }, + { name: 'new-options-page', label: __('Create New Options Page', 'secure-custom-fields'), url: 'admin.php?page=acf-ui-options-page' }, + { name: 'tools', label: __('SCF Tools', 'secure-custom-fields'), url: 'admin.php?page=acf-tools' }, + { name: 'import', label: __('Import SCF Data', 'secure-custom-fields'), url: 'admin.php?page=acf-tools&tool=import' }, + { name: 'export', label: __('Export SCF Data', 'secure-custom-fields'), url: 'admin.php?page=acf-tools&tool=export' } + ]; + + // Register each command + commands.forEach(command => { + commandStore.registerCommand({ + name: 'scf/' + command.name, + label: command.label, + context: 'admin', + callback: () => { + window.location.href = command.url; + } + }); + }); +}); \ No newline at end of file diff --git a/includes/assets.php b/includes/assets.php index 6793e273..431da3ff 100644 --- a/includes/assets.php +++ b/includes/assets.php @@ -242,6 +242,12 @@ public function register_scripts() { $script['in_footer'] ); } + wp_register_script( 'acf', acf_get_url( 'assets/build/js/acf' . $suffix . '.js' ), array( 'jquery' ), $version, false ); + wp_register_script( 'acf-input', acf_get_url( 'assets/build/js/acf-input' . $suffix . '.js' ), array( 'jquery', 'jquery-ui-sortable', 'jquery-ui-resizable', 'acf', 'wp-a11y' ), $version, false ); + wp_register_script( 'acf-command-palette', acf_get_url( 'assets/build/js/acf-command-palette' . $suffix . '.js' ), array( 'acf', 'wp-plugins', 'wp-element', 'wp-components', 'wp-data', 'wp-commands', 'wp-i18n', 'wp-dom-ready' ), $version, true ); + wp_register_script( 'acf-field-group', acf_get_url( 'assets/build/js/acf-field-group' . $suffix . '.js' ), array( 'acf-input' ), $version, false ); + wp_register_script( 'acf-internal-post-type', acf_get_url( 'assets/build/js/acf-internal-post-type' . $suffix . '.js' ), array( 'acf-input' ), $version, false ); + wp_register_script( 'acf-escaped-html-notice', acf_get_url( 'assets/build/js/acf-escaped-html-notice' . $suffix . '.js' ), array( 'jquery' ), $version, true ); // Register styles. foreach ( $styles as $style ) { @@ -262,6 +268,13 @@ public function register_scripts() { * @param string $suffix The potential ".min" filename suffix. */ do_action( 'acf/register_scripts', $version, $suffix ); + + // Ensure WordPress scripts needed for command palette integration are available + if ( function_exists( 'wp_enqueue_script' ) ) { + wp_enqueue_script( 'wp-commands' ); + wp_enqueue_script( 'wp-i18n' ); + wp_enqueue_script( 'wp-dom-ready' ); + } } /** diff --git a/secure-custom-fields.php b/secure-custom-fields.php index 87c872fc..c1aef0e8 100644 --- a/secure-custom-fields.php +++ b/secure-custom-fields.php @@ -229,6 +229,38 @@ public function initialize() { // Add filters. add_filter( 'posts_where', array( $this, 'posts_where' ), 10, 2 ); + + // Load command palette + add_action( 'admin_enqueue_scripts', array( $this, 'load_command_palette' ) ); + } + + /** + * Loads the command palette script and its dependencies + * + * @since 6.4.1 + */ + public function load_command_palette() { + // Only load on admin screens + if ( ! is_admin() ) { + return; + } + + // Enqueue necessary WordPress dependencies for the command palette + wp_enqueue_script( 'wp-plugins' ); + wp_enqueue_script( 'wp-element' ); + wp_enqueue_script( 'wp-components' ); + wp_enqueue_script( 'wp-data' ); + wp_enqueue_script( 'wp-commands' ); + wp_enqueue_script( 'wp-i18n' ); + wp_enqueue_script( 'wp-dom-ready' ); + + // Prepare the script URL with proper suffix + $suffix = defined( 'SCF_DEVELOPMENT_MODE' ) && SCF_DEVELOPMENT_MODE ? '' : '.min'; + $version = acf_get_setting( 'version' ); + + // Enqueue the command palette script which was registered in assets.php + // The script uses the WordPress plugins API to properly integrate with the command palette + wp_enqueue_script( 'acf-command-palette' ); } /** diff --git a/webpack.config.js b/webpack.config.js index e44cab84..08998ddd 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -15,6 +15,7 @@ const commonConfig = { 'js/acf-input': './assets/src/js/acf-input.js', 'js/acf-internal-post-type': './assets/src/js/acf-internal-post-type.js', + 'js/acf-command-palette': './assets/src/js/acf-command-palette.js', 'js/acf': './assets/src/js/acf.js', 'js/pro/acf-pro-blocks': './assets/src/js/pro/acf-pro-blocks.js', 'js/pro/acf-pro-field-group': From d6006fec465e78286e3c417dc49efa36fc216fb1 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Thu, 17 Apr 2025 19:56:41 +0200 Subject: [PATCH 02/33] Command polishing --- assets/src/js/acf-command-palette.js | 109 +++++++++++++++++++++++---- secure-custom-fields.php | 2 +- 2 files changed, 97 insertions(+), 14 deletions(-) diff --git a/assets/src/js/acf-command-palette.js b/assets/src/js/acf-command-palette.js index 50bc3824..f238543e 100644 --- a/assets/src/js/acf-command-palette.js +++ b/assets/src/js/acf-command-palette.js @@ -2,6 +2,9 @@ * SCF Command Palette integration * * Uses WordPress Commands API to add Secure Custom Fields commands to the WordPress command palette. + * Enhances the user experience with icons, descriptions, and keywords for better discoverability. + * + * @since 6.5.0 */ // Register commands when WordPress is ready @@ -18,27 +21,107 @@ wp.domReady(() => { // Get the commands store const commandStore = wp.data.dispatch('core/commands'); - // Command definitions for SCF admin pages + // Command definitions for SCF admin pages with improved metadata const commands = [ - { name: 'field-groups', label: __('Field Groups', 'secure-custom-fields'), url: 'edit.php?post_type=acf-field-group' }, - { name: 'new-field-group', label: __('Create New Field Group', 'secure-custom-fields'), url: 'post-new.php?post_type=acf-field-group' }, - { name: 'post-types', label: __('Post Types', 'secure-custom-fields'), url: 'admin.php?page=acf-post-types' }, - { name: 'new-post-type', label: __('Create New Post Type', 'secure-custom-fields'), url: 'admin.php?page=acf-post-type' }, - { name: 'taxonomies', label: __('Taxonomies', 'secure-custom-fields'), url: 'admin.php?page=acf-taxonomies' }, - { name: 'new-taxonomy', label: __('Create New Taxonomy', 'secure-custom-fields'), url: 'admin.php?page=acf-taxonomy' }, - { name: 'options-pages', label: __('Options Pages', 'secure-custom-fields'), url: 'admin.php?page=acf-options-pages' }, - { name: 'new-options-page', label: __('Create New Options Page', 'secure-custom-fields'), url: 'admin.php?page=acf-ui-options-page' }, - { name: 'tools', label: __('SCF Tools', 'secure-custom-fields'), url: 'admin.php?page=acf-tools' }, - { name: 'import', label: __('Import SCF Data', 'secure-custom-fields'), url: 'admin.php?page=acf-tools&tool=import' }, - { name: 'export', label: __('Export SCF Data', 'secure-custom-fields'), url: 'admin.php?page=acf-tools&tool=export' } + { + name: 'field-groups', + label: __('Field Groups', 'secure-custom-fields'), + url: 'edit.php?post_type=acf-field-group', + icon: 'layout', + description: __('SCF: View and manage custom field groups', 'secure-custom-fields'), + keywords: ['acf', 'custom fields', 'field editor', 'manage fields'] + }, + { + name: 'new-field-group', + label: __('Create New Field Group', 'secure-custom-fields'), + url: 'post-new.php?post_type=acf-field-group', + icon: 'plus', + description: __('SCF: Create a new field group to organize custom fields', 'secure-custom-fields'), + keywords: ['add', 'new', 'create', 'field group', 'custom fields'] + }, + { + name: 'post-types', + label: __('Post Types', 'secure-custom-fields'), + url: 'admin.php?page=acf-post-types', + icon: 'admin-post', + description: __('SCF: Manage custom post types', 'secure-custom-fields'), + keywords: ['cpt', 'content types', 'manage post types'] + }, + { + name: 'new-post-type', + label: __('Create New Post Type', 'secure-custom-fields'), + url: 'admin.php?page=acf-post-type', + icon: 'plus', + description: __('SCF: Create a new custom post type', 'secure-custom-fields'), + keywords: ['add', 'new', 'create', 'cpt', 'content type'] + }, + { + name: 'taxonomies', + label: __('Taxonomies', 'secure-custom-fields'), + url: 'admin.php?page=acf-taxonomies', + icon: 'category', + description: __('SCF: Manage custom taxonomies for organizing content', 'secure-custom-fields'), + keywords: ['categories', 'tags', 'terms', 'custom taxonomies'] + }, + { + name: 'new-taxonomy', + label: __('Create New Taxonomy', 'secure-custom-fields'), + url: 'admin.php?page=acf-taxonomy', + icon: 'plus', + description: __('SCF: Create a new custom taxonomy', 'secure-custom-fields'), + keywords: ['add', 'new', 'create', 'taxonomy', 'categories', 'tags'] + }, + { + name: 'options-pages', + label: __('Options Pages', 'secure-custom-fields'), + url: 'admin.php?page=acf-options-pages', + icon: 'admin-settings', + description: __('SCF: Manage custom options pages for global settings', 'secure-custom-fields'), + keywords: ['settings', 'global options', 'site options'] + }, + { + name: 'new-options-page', + label: __('Create New Options Page', 'secure-custom-fields'), + url: 'admin.php?page=acf-ui-options-page', + icon: 'plus', + description: __('SCF: Create a new custom options page', 'secure-custom-fields'), + keywords: ['add', 'new', 'create', 'options', 'settings page'] + }, + { + name: 'tools', + label: __('SCF Tools', 'secure-custom-fields'), + url: 'admin.php?page=acf-tools', + icon: 'admin-tools', + description: __('SCF: Access SCF utility tools', 'secure-custom-fields'), + keywords: ['utilities', 'import export', 'json'] + }, + { + name: 'import', + label: __('Import SCF Data', 'secure-custom-fields'), + url: 'admin.php?page=acf-tools&tool=import', + icon: 'upload', + description: __('SCF: Import field groups, post types, taxonomies, and options pages', 'secure-custom-fields'), + keywords: ['upload', 'json', 'migration', 'transfer'] + }, + { + name: 'export', + label: __('Export SCF Data', 'secure-custom-fields'), + url: 'admin.php?page=acf-tools&tool=export', + icon: 'download', + description: __('SCF: Export field groups, post types, taxonomies, and options pages', 'secure-custom-fields'), + keywords: ['download', 'json', 'backup', 'migration'] + } ]; - // Register each command + // Register each command with enhanced metadata commands.forEach(command => { commandStore.registerCommand({ name: 'scf/' + command.name, label: command.label, + icon: command.icon, context: 'admin', + description: command.description, + keywords: command.keywords, callback: () => { window.location.href = command.url; } diff --git a/secure-custom-fields.php b/secure-custom-fields.php index c1aef0e8..45b74603 100644 --- a/secure-custom-fields.php +++ b/secure-custom-fields.php @@ -237,7 +237,7 @@ public function initialize() { /** * Loads the command palette script and its dependencies * - * @since 6.4.1 + * @since 6.5.0 */ public function load_command_palette() { // Only load on admin screens From 4ec2af9f89b7090f18da5768888e12d9b4135728 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Thu, 17 Apr 2025 21:07:48 +0200 Subject: [PATCH 03/33] Add commands for registered CPTs --- assets/src/js/acf-command-palette.js | 64 ++++++++++++++++++++++++++-- debug-command-palette.js | 1 + secure-custom-fields.php | 49 ++++++++++++++++++++- 3 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 debug-command-palette.js diff --git a/assets/src/js/acf-command-palette.js b/assets/src/js/acf-command-palette.js index f238543e..3efb144d 100644 --- a/assets/src/js/acf-command-palette.js +++ b/assets/src/js/acf-command-palette.js @@ -11,18 +11,21 @@ wp.domReady(() => { // Make sure required WordPress dependencies are available if (!wp.data || !wp.data.dispatch || !wp.data.dispatch('core/commands')) { - console.warn('SCF Command Palette: WordPress Commands API not available'); return; } - // Access the WordPress i18n functions + // Access the WordPress i18n functions and components const { __ } = wp.i18n; + const { createElement } = wp.element; // Get the commands store const commandStore = wp.data.dispatch('core/commands'); + // Get WP Components + const { Icon } = wp.components; + // Command definitions for SCF admin pages with improved metadata - const commands = [ + let commands = [ { name: 'field-groups', label: __('Field Groups', 'secure-custom-fields'), @@ -113,12 +116,65 @@ wp.domReady(() => { } ]; + // Add commands for user-created custom post types if available + if (window.scfCommandPaletteData && window.scfCommandPaletteData.customPostTypes) { + const customPostTypes = window.scfCommandPaletteData.customPostTypes; + + // Validate the customPostTypes is an array + if (!Array.isArray(customPostTypes)) { + return; + } + + // Add each custom post type as a command + customPostTypes.forEach((postType, index) => { + // Validate postType is an object + if (!postType || typeof postType !== 'object') { + return; + } + + // Skip if postType.name is missing or invalid + if (!postType.name || typeof postType.name !== 'string') { + return; + } + + // Determine label with fallback + const pluralLabel = postType.label ? postType.label : postType.name; + const singularLabel = postType.singular_label || pluralLabel; + + // Add command to view all posts of this type + commands.push({ + name: `cpt-${postType.name}`, + label: pluralLabel, + url: `edit.php?post_type=${postType.name}`, + icon: 'admin-page', // Using standard dashicon for better visibility + description: __('SCF: View all', 'secure-custom-fields') + ` ${pluralLabel}`, + keywords: ['post type', 'content', 'cpt', postType.name, postType.label || ''] + }); + + // Also add command to add new post of this type + commands.push({ + name: `new-${postType.name}`, + label: __('Add New', 'secure-custom-fields') + ` ${singularLabel}`, + url: `post-new.php?post_type=${postType.name}`, + icon: 'plus', + description: __('SCF: Create a new', 'secure-custom-fields') + ` ${singularLabel}`, + keywords: ['add', 'new', 'create', 'content', postType.name, postType.label || ''] + }); + }); + } + + // Create icon component function + const createIconComponent = (iconName) => { + // Return a function that creates the icon element + return createElement(Icon, { icon: iconName }); + }; + // Register each command with enhanced metadata commands.forEach(command => { commandStore.registerCommand({ name: 'scf/' + command.name, label: command.label, - icon: command.icon, + icon: createIconComponent(command.icon), context: 'admin', description: command.description, keywords: command.keywords, diff --git a/debug-command-palette.js b/debug-command-palette.js new file mode 100644 index 00000000..a49fdc23 --- /dev/null +++ b/debug-command-palette.js @@ -0,0 +1 @@ +console.log('SCF Command Palette Data:', window.scfCommandPaletteData); diff --git a/secure-custom-fields.php b/secure-custom-fields.php index 45b74603..294a8286 100644 --- a/secure-custom-fields.php +++ b/secure-custom-fields.php @@ -258,6 +258,53 @@ public function load_command_palette() { $suffix = defined( 'SCF_DEVELOPMENT_MODE' ) && SCF_DEVELOPMENT_MODE ? '' : '.min'; $version = acf_get_setting( 'version' ); + // Get all SCF custom post types to add to command palette + $custom_post_types = array(); + + // Get SCF post type definitions + if ( function_exists( 'acf_get_acf_post_types' ) ) { + $scf_post_types = acf_get_acf_post_types(); + + foreach ( $scf_post_types as $post_type ) { + if ( isset( $post_type['post_type'] ) && isset( $post_type['active'] ) && $post_type['active'] ) { + // Get both plural and singular labels using null coalescing operator + $plural_label = $post_type['labels']['name'] ?? $post_type['label'] ?? $post_type['post_type']; + $singular_label = $post_type['labels']['singular_name'] ?? $post_type['singular_label'] ?? $plural_label; + + $custom_post_types[] = array( + 'name' => $post_type['post_type'], + 'label' => $plural_label, + 'singular_label' => $singular_label, + 'icon' => $post_type['menu_icon'] ?? '', + 'source' => 'scf', + ); + } + } + } + + // Localize the data for the command palette + wp_localize_script( + 'acf-command-palette', + 'scfCommandPaletteData', + array( + 'customPostTypes' => $custom_post_types, + 'version' => acf_get_setting( 'version' ), + 'isDevelopmentMode' => defined( 'SCF_DEVELOPMENT_MODE' ) && SCF_DEVELOPMENT_MODE, + 'pluginUrl' => acf_get_setting( 'url' ), + 'adminUrl' => admin_url(), + 'ajaxUrl' => admin_url( 'admin-ajax.php' ), + 'currentScreen' => array( + 'id' => function_exists( 'get_current_screen' ) ? get_current_screen()->id : '', + 'base' => function_exists( 'get_current_screen' ) ? get_current_screen()->base : '', + ), + 'debug' => array( + 'enabled' => defined( 'WP_DEBUG' ) && WP_DEBUG, + 'scriptLoaded' => true, + 'timestamp' => time(), + ), + ) + ); + // Enqueue the command palette script which was registered in assets.php // The script uses the WordPress plugins API to properly integrate with the command palette wp_enqueue_script( 'acf-command-palette' ); @@ -872,4 +919,4 @@ function scf_plugin_deactivated_notice() { } add_action( 'pre_current_active_plugins', 'scf_plugin_deactivated_notice' ); -} +} \ No newline at end of file From 18e250f7521de6de99d1b9259bbacc8b4a546691 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Thu, 17 Apr 2025 21:32:39 +0200 Subject: [PATCH 04/33] Refactor --- assets/src/js/acf-command-palette.js | 200 ++++----------------------- secure-custom-fields.php | 61 ++++---- webpack.config.js | 14 +- 3 files changed, 65 insertions(+), 210 deletions(-) diff --git a/assets/src/js/acf-command-palette.js b/assets/src/js/acf-command-palette.js index 3efb144d..6f985a1a 100644 --- a/assets/src/js/acf-command-palette.js +++ b/assets/src/js/acf-command-palette.js @@ -7,180 +7,40 @@ * @since 6.5.0 */ -// Register commands when WordPress is ready -wp.domReady(() => { - // Make sure required WordPress dependencies are available - if (!wp.data || !wp.data.dispatch || !wp.data.dispatch('core/commands')) { - return; - } - - // Access the WordPress i18n functions and components - const { __ } = wp.i18n; - const { createElement } = wp.element; +/** + * Register SCF commands in the command palette + */ +const registerSCFCommands = () => { + // Register a command group for SCF + wp.commands.registerCommand({ + name: 'scf-group', + label: wp.i18n.__('Secure Custom Fields', 'secure-custom-fields'), + group: 'secure-custom-fields', + }); - // Get the commands store - const commandStore = wp.data.dispatch('core/commands'); - - // Get WP Components - const { Icon } = wp.components; + // Register commands for each post type + const postTypes = window._scfData?.customPostTypes || []; - // Command definitions for SCF admin pages with improved metadata - let commands = [ - { - name: 'field-groups', - label: __('Field Groups', 'secure-custom-fields'), - url: 'edit.php?post_type=acf-field-group', - icon: 'layout', - description: __('SCF: View and manage custom field groups', 'secure-custom-fields'), - keywords: ['acf', 'custom fields', 'field editor', 'manage fields'] - }, - { - name: 'new-field-group', - label: __('Create New Field Group', 'secure-custom-fields'), - url: 'post-new.php?post_type=acf-field-group', - icon: 'plus', - description: __('SCF: Create a new field group to organize custom fields', 'secure-custom-fields'), - keywords: ['add', 'new', 'create', 'field group', 'custom fields'] - }, - { - name: 'post-types', - label: __('Post Types', 'secure-custom-fields'), - url: 'admin.php?page=acf-post-types', - icon: 'admin-post', - description: __('SCF: Manage custom post types', 'secure-custom-fields'), - keywords: ['cpt', 'content types', 'manage post types'] - }, - { - name: 'new-post-type', - label: __('Create New Post Type', 'secure-custom-fields'), - url: 'admin.php?page=acf-post-type', - icon: 'plus', - description: __('SCF: Create a new custom post type', 'secure-custom-fields'), - keywords: ['add', 'new', 'create', 'cpt', 'content type'] - }, - { - name: 'taxonomies', - label: __('Taxonomies', 'secure-custom-fields'), - url: 'admin.php?page=acf-taxonomies', - icon: 'category', - description: __('SCF: Manage custom taxonomies for organizing content', 'secure-custom-fields'), - keywords: ['categories', 'tags', 'terms', 'custom taxonomies'] - }, - { - name: 'new-taxonomy', - label: __('Create New Taxonomy', 'secure-custom-fields'), - url: 'admin.php?page=acf-taxonomy', - icon: 'plus', - description: __('SCF: Create a new custom taxonomy', 'secure-custom-fields'), - keywords: ['add', 'new', 'create', 'taxonomy', 'categories', 'tags'] - }, - { - name: 'options-pages', - label: __('Options Pages', 'secure-custom-fields'), - url: 'admin.php?page=acf-options-pages', - icon: 'admin-settings', - description: __('SCF: Manage custom options pages for global settings', 'secure-custom-fields'), - keywords: ['settings', 'global options', 'site options'] - }, - { - name: 'new-options-page', - label: __('Create New Options Page', 'secure-custom-fields'), - url: 'admin.php?page=acf-ui-options-page', - icon: 'plus', - description: __('SCF: Create a new custom options page', 'secure-custom-fields'), - keywords: ['add', 'new', 'create', 'options', 'settings page'] - }, - { - name: 'tools', - label: __('SCF Tools', 'secure-custom-fields'), - url: 'admin.php?page=acf-tools', - icon: 'admin-tools', - description: __('SCF: Access SCF utility tools', 'secure-custom-fields'), - keywords: ['utilities', 'import export', 'json'] - }, - { - name: 'import', - label: __('Import SCF Data', 'secure-custom-fields'), - url: 'admin.php?page=acf-tools&tool=import', - icon: 'upload', - description: __('SCF: Import field groups, post types, taxonomies, and options pages', 'secure-custom-fields'), - keywords: ['upload', 'json', 'migration', 'transfer'] - }, - { - name: 'export', - label: __('Export SCF Data', 'secure-custom-fields'), - url: 'admin.php?page=acf-tools&tool=export', - icon: 'download', - description: __('SCF: Export field groups, post types, taxonomies, and options pages', 'secure-custom-fields'), - keywords: ['download', 'json', 'backup', 'migration'] - } - ]; - - // Add commands for user-created custom post types if available - if (window.scfCommandPaletteData && window.scfCommandPaletteData.customPostTypes) { - const customPostTypes = window.scfCommandPaletteData.customPostTypes; - - // Validate the customPostTypes is an array - if (!Array.isArray(customPostTypes)) { - return; - } - - // Add each custom post type as a command - customPostTypes.forEach((postType, index) => { - // Validate postType is an object - if (!postType || typeof postType !== 'object') { - return; - } - - // Skip if postType.name is missing or invalid - if (!postType.name || typeof postType.name !== 'string') { - return; - } - - // Determine label with fallback - const pluralLabel = postType.label ? postType.label : postType.name; - const singularLabel = postType.singular_label || pluralLabel; - - // Add command to view all posts of this type - commands.push({ - name: `cpt-${postType.name}`, - label: pluralLabel, - url: `edit.php?post_type=${postType.name}`, - icon: 'admin-page', // Using standard dashicon for better visibility - description: __('SCF: View all', 'secure-custom-fields') + ` ${pluralLabel}`, - keywords: ['post type', 'content', 'cpt', postType.name, postType.label || ''] - }); - - // Also add command to add new post of this type - commands.push({ - name: `new-${postType.name}`, - label: __('Add New', 'secure-custom-fields') + ` ${singularLabel}`, - url: `post-new.php?post_type=${postType.name}`, - icon: 'plus', - description: __('SCF: Create a new', 'secure-custom-fields') + ` ${singularLabel}`, - keywords: ['add', 'new', 'create', 'content', postType.name, postType.label || ''] - }); + postTypes.forEach((postType) => { + wp.commands.registerCommand({ + name: `scf-list-${postType.name}`, + label: wp.i18n.__(`List ${postType.label}`, 'secure-custom-fields'), + callback: () => { + window.location.href = `${window._scfData.adminUrl}edit.php?post_type=${postType.name}`; + }, + group: 'secure-custom-fields', }); - } - - // Create icon component function - const createIconComponent = (iconName) => { - // Return a function that creates the icon element - return createElement(Icon, { icon: iconName }); - }; - // Register each command with enhanced metadata - commands.forEach(command => { - commandStore.registerCommand({ - name: 'scf/' + command.name, - label: command.label, - icon: createIconComponent(command.icon), - context: 'admin', - description: command.description, - keywords: command.keywords, + wp.commands.registerCommand({ + name: `scf-new-${postType.name}`, + label: wp.i18n.__(`New ${postType.singular_label}`, 'secure-custom-fields'), callback: () => { - window.location.href = command.url; - } + window.location.href = `${window._scfData.adminUrl}post-new.php?post_type=${postType.name}`; + }, + group: 'secure-custom-fields', }); }); -}); \ No newline at end of file +} + +// Register commands when DOM is ready +wp.domReady(registerSCFCommands); \ No newline at end of file diff --git a/secure-custom-fields.php b/secure-custom-fields.php index 294a8286..0ec491c3 100644 --- a/secure-custom-fields.php +++ b/secure-custom-fields.php @@ -245,19 +245,6 @@ public function load_command_palette() { return; } - // Enqueue necessary WordPress dependencies for the command palette - wp_enqueue_script( 'wp-plugins' ); - wp_enqueue_script( 'wp-element' ); - wp_enqueue_script( 'wp-components' ); - wp_enqueue_script( 'wp-data' ); - wp_enqueue_script( 'wp-commands' ); - wp_enqueue_script( 'wp-i18n' ); - wp_enqueue_script( 'wp-dom-ready' ); - - // Prepare the script URL with proper suffix - $suffix = defined( 'SCF_DEVELOPMENT_MODE' ) && SCF_DEVELOPMENT_MODE ? '' : '.min'; - $version = acf_get_setting( 'version' ); - // Get all SCF custom post types to add to command palette $custom_post_types = array(); @@ -276,37 +263,45 @@ public function load_command_palette() { 'label' => $plural_label, 'singular_label' => $singular_label, 'icon' => $post_type['menu_icon'] ?? '', - 'source' => 'scf', ); } } } - // Localize the data for the command palette + // Enqueue necessary WordPress dependencies for the command palette + wp_enqueue_script( 'wp-plugins' ); + wp_enqueue_script( 'wp-element' ); + wp_enqueue_script( 'wp-components' ); + wp_enqueue_script( 'wp-data' ); + wp_enqueue_script( 'wp-commands' ); + wp_enqueue_script( 'wp-i18n' ); + wp_enqueue_script( 'wp-dom-ready' ); + + // Register and enqueue our command palette script + $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; + $version = acf_get_setting( 'version' ); + + // First deregister the script if it was registered before + wp_deregister_script( 'acf-command-palette' ); + + wp_register_script( + 'acf-command-palette', + acf_get_setting( 'url' ) . "assets/build/js/acf-command-palette{$suffix}.js", + array( 'wp-data', 'wp-i18n', 'wp-dom-ready' ), + $version, + true + ); + + // Localize minimal data needed for commands wp_localize_script( 'acf-command-palette', - 'scfCommandPaletteData', + '_scfData', array( - 'customPostTypes' => $custom_post_types, - 'version' => acf_get_setting( 'version' ), - 'isDevelopmentMode' => defined( 'SCF_DEVELOPMENT_MODE' ) && SCF_DEVELOPMENT_MODE, - 'pluginUrl' => acf_get_setting( 'url' ), - 'adminUrl' => admin_url(), - 'ajaxUrl' => admin_url( 'admin-ajax.php' ), - 'currentScreen' => array( - 'id' => function_exists( 'get_current_screen' ) ? get_current_screen()->id : '', - 'base' => function_exists( 'get_current_screen' ) ? get_current_screen()->base : '', - ), - 'debug' => array( - 'enabled' => defined( 'WP_DEBUG' ) && WP_DEBUG, - 'scriptLoaded' => true, - 'timestamp' => time(), - ), + 'customPostTypes' => $custom_post_types, + 'adminUrl' => admin_url(), ) ); - // Enqueue the command palette script which was registered in assets.php - // The script uses the WordPress plugins API to properly integrate with the command palette wp_enqueue_script( 'acf-command-palette' ); } diff --git a/webpack.config.js b/webpack.config.js index 08998ddd..81f74eac 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -44,7 +44,7 @@ const commonConfig = { use: { loader: 'babel-loader', options: { - presets: [ '@babel/preset-react' ], + presets: ['@babel/preset-react'], }, }, }, @@ -81,11 +81,11 @@ const unminifiedConfig = { new RemoveEmptyScriptsPlugin(), new MiniCssExtractPlugin( { filename: '[name].css', // Output CSS as .css - } ), - new DependencyExtractionWebpackPlugin( { + }), + new DependencyExtractionWebpackPlugin({ injectPolyfill: true, useCombinedAssetFile: true, - } ), + }), ], }; @@ -115,11 +115,11 @@ const minifiedConfig = { new RemoveEmptyScriptsPlugin(), new MiniCssExtractPlugin( { filename: '[name].min.css', // Changed to output .min.css files - } ), - new DependencyExtractionWebpackPlugin( { + }), + new DependencyExtractionWebpackPlugin({ injectPolyfill: true, useCombinedAssetFile: true, - } ), + }), ], }; From 77bdff196463c600742ef6dcf79f0194c655de04 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Thu, 17 Apr 2025 21:48:26 +0200 Subject: [PATCH 05/33] Refactor to use wp.scf --- assets/src/js/acf-command-palette.js | 24 +++++++++++++++++------- secure-custom-fields.php | 18 +++++++++++------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/assets/src/js/acf-command-palette.js b/assets/src/js/acf-command-palette.js index 6f985a1a..f158f69c 100644 --- a/assets/src/js/acf-command-palette.js +++ b/assets/src/js/acf-command-palette.js @@ -11,31 +11,41 @@ * Register SCF commands in the command palette */ const registerSCFCommands = () => { + // Make sure required WordPress dependencies are available + if (!wp.data || !wp.data.dispatch || !wp.data.dispatch('core/commands')) { + console.warn('Secure Custom Fields: WordPress Commands API not available'); + return; + } + + // Get the commands store + const commandStore = wp.data.dispatch('core/commands'); + // Register a command group for SCF - wp.commands.registerCommand({ + commandStore.registerCommand({ name: 'scf-group', label: wp.i18n.__('Secure Custom Fields', 'secure-custom-fields'), group: 'secure-custom-fields', }); - // Register commands for each post type - const postTypes = window._scfData?.customPostTypes || []; + // Register commands for each post type using properly namespaced WordPress data + const postTypes = wp.scf?.commandData?.customPostTypes || []; + const adminUrl = wp.scf?.commandData?.adminUrl || ''; postTypes.forEach((postType) => { - wp.commands.registerCommand({ + commandStore.registerCommand({ name: `scf-list-${postType.name}`, label: wp.i18n.__(`List ${postType.label}`, 'secure-custom-fields'), callback: () => { - window.location.href = `${window._scfData.adminUrl}edit.php?post_type=${postType.name}`; + window.location.href = `${adminUrl}edit.php?post_type=${postType.name}`; }, group: 'secure-custom-fields', }); - wp.commands.registerCommand({ + commandStore.registerCommand({ name: `scf-new-${postType.name}`, label: wp.i18n.__(`New ${postType.singular_label}`, 'secure-custom-fields'), callback: () => { - window.location.href = `${window._scfData.adminUrl}post-new.php?post_type=${postType.name}`; + window.location.href = `${adminUrl}post-new.php?post_type=${postType.name}`; }, group: 'secure-custom-fields', }); diff --git a/secure-custom-fields.php b/secure-custom-fields.php index 0ec491c3..bbd7287a 100644 --- a/secure-custom-fields.php +++ b/secure-custom-fields.php @@ -292,14 +292,18 @@ public function load_command_palette() { true ); - // Localize minimal data needed for commands - wp_localize_script( + // Set up data as a property of wp object to follow WordPress conventions + wp_add_inline_script( 'acf-command-palette', - '_scfData', - array( - 'customPostTypes' => $custom_post_types, - 'adminUrl' => admin_url(), - ) + 'window.wp = window.wp || {}; wp.scf = ' . wp_json_encode( + array( + 'commandData' => array( + 'customPostTypes' => $custom_post_types, + 'adminUrl' => admin_url(), + ), + ) + ) . ';', + 'before' ); wp_enqueue_script( 'acf-command-palette' ); From b8894cfac0d2184c10b41bf8c9f1ae5ddca4f55d Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Fri, 18 Apr 2025 16:27:55 +0200 Subject: [PATCH 06/33] Refactor --- assets/src/js/acf-command-palette.js | 180 +++++++++++++++++++++------ secure-custom-fields.php | 41 ++---- 2 files changed, 156 insertions(+), 65 deletions(-) diff --git a/assets/src/js/acf-command-palette.js b/assets/src/js/acf-command-palette.js index f158f69c..98af2e7d 100644 --- a/assets/src/js/acf-command-palette.js +++ b/assets/src/js/acf-command-palette.js @@ -7,50 +7,160 @@ * @since 6.5.0 */ -/** - * Register SCF commands in the command palette - */ -const registerSCFCommands = () => { +// Register commands when WordPress is ready +wp.domReady(() => { // Make sure required WordPress dependencies are available if (!wp.data || !wp.data.dispatch || !wp.data.dispatch('core/commands')) { - console.warn('Secure Custom Fields: WordPress Commands API not available'); return; } - - // Get the commands store + + // Access essential WordPress functions and data + const { __ } = wp.i18n; + const { createElement } = wp.element; + const { Icon } = wp.components; const commandStore = wp.data.dispatch('core/commands'); - // Register a command group for SCF - commandStore.registerCommand({ - name: 'scf-group', - label: wp.i18n.__('Secure Custom Fields', 'secure-custom-fields'), - group: 'secure-custom-fields', - }); - - // Register commands for each post type using properly namespaced WordPress data - const postTypes = wp.scf?.commandData?.customPostTypes || []; - const adminUrl = wp.scf?.commandData?.adminUrl || ''; + // Get data from namespace + const adminUrl = wp.scf?.commands?.adminUrl || ''; + const postTypes = wp.scf?.commands?.postTypes || []; - postTypes.forEach((postType) => { - commandStore.registerCommand({ - name: `scf-list-${postType.name}`, - label: wp.i18n.__(`List ${postType.label}`, 'secure-custom-fields'), - callback: () => { - window.location.href = `${adminUrl}edit.php?post_type=${postType.name}`; - }, - group: 'secure-custom-fields', + // Command definitions for SCF admin pages with improved metadata + let commands = [ + { + name: 'field-groups', + label: __('Field Groups', 'secure-custom-fields'), + url: `${adminUrl}edit.php?post_type=acf-field-group`, + icon: 'layout', + description: __('SCF: View and manage custom field groups', 'secure-custom-fields'), + keywords: ['acf', 'custom fields', 'field editor', 'manage fields'] + }, + { + name: 'new-field-group', + label: __('Create New Field Group', 'secure-custom-fields'), + url: `${adminUrl}post-new.php?post_type=acf-field-group`, + icon: 'plus', + description: __('SCF: Create a new field group to organize custom fields', 'secure-custom-fields'), + keywords: ['add', 'new', 'create', 'field group', 'custom fields'] + }, + { + name: 'post-types', + label: __('Post Types', 'secure-custom-fields'), + url: `${adminUrl}admin.php?page=acf-post-types`, + icon: 'admin-post', + description: __('SCF: Manage custom post types', 'secure-custom-fields'), + keywords: ['cpt', 'content types', 'manage post types'] + }, + { + name: 'new-post-type', + label: __('Create New Post Type', 'secure-custom-fields'), + url: `${adminUrl}admin.php?page=acf-post-type`, + icon: 'plus', + description: __('SCF: Create a new custom post type', 'secure-custom-fields'), + keywords: ['add', 'new', 'create', 'cpt', 'content type'] + }, + { + name: 'taxonomies', + label: __('Taxonomies', 'secure-custom-fields'), + url: `${adminUrl}admin.php?page=acf-taxonomies`, + icon: 'category', + description: __('SCF: Manage custom taxonomies for organizing content', 'secure-custom-fields'), + keywords: ['categories', 'tags', 'terms', 'custom taxonomies'] + }, + { + name: 'new-taxonomy', + label: __('Create New Taxonomy', 'secure-custom-fields'), + url: `${adminUrl}admin.php?page=acf-taxonomy`, + icon: 'plus', + description: __('SCF: Create a new custom taxonomy', 'secure-custom-fields'), + keywords: ['add', 'new', 'create', 'taxonomy', 'categories', 'tags'] + }, + { + name: 'options-pages', + label: __('Options Pages', 'secure-custom-fields'), + url: `${adminUrl}admin.php?page=acf-options-pages`, + icon: 'admin-settings', + description: __('SCF: Manage custom options pages for global settings', 'secure-custom-fields'), + keywords: ['settings', 'global options', 'site options'] + }, + { + name: 'new-options-page', + label: __('Create New Options Page', 'secure-custom-fields'), + url: `${adminUrl}admin.php?page=acf-ui-options-page`, + icon: 'plus', + description: __('SCF: Create a new custom options page', 'secure-custom-fields'), + keywords: ['add', 'new', 'create', 'options', 'settings page'] + }, + { + name: 'tools', + label: __('SCF Tools', 'secure-custom-fields'), + url: `${adminUrl}admin.php?page=acf-tools`, + icon: 'admin-tools', + description: __('SCF: Access SCF utility tools', 'secure-custom-fields'), + keywords: ['utilities', 'import export', 'json'] + }, + { + name: 'import', + label: __('Import SCF Data', 'secure-custom-fields'), + url: `${adminUrl}admin.php?page=acf-tools&tool=import`, + icon: 'upload', + description: __('SCF: Import field groups, post types, taxonomies, and options pages', 'secure-custom-fields'), + keywords: ['upload', 'json', 'migration', 'transfer'] + }, + { + name: 'export', + label: __('Export SCF Data', 'secure-custom-fields'), + url: `${adminUrl}admin.php?page=acf-tools&tool=export`, + icon: 'download', + description: __('SCF: Export field groups, post types, taxonomies, and options pages', 'secure-custom-fields'), + keywords: ['download', 'json', 'backup', 'migration'] + } + ]; + + // Add commands for user-created custom post types + if (postTypes && postTypes.length > 0) { + // Add each custom post type as a command + postTypes.forEach(postType => { + // Skip invalid post types + if (!postType?.name) return; + + // Get labels + const pluralLabel = postType.label || postType.name; + const singularLabel = postType.singular_label || pluralLabel; + + // Add command to view all posts of this type + commands.push({ + name: `cpt-${postType.name}`, + label: pluralLabel, + url: `${adminUrl}edit.php?post_type=${postType.name}`, + icon: 'admin-page', // Using standard dashicon for better visibility + description: __('SCF: View all', 'secure-custom-fields') + ` ${pluralLabel}`, + keywords: ['post type', 'content', 'cpt', postType.name, postType.label || ''] + }); + + // Also add command to add new post of this type + commands.push({ + name: `new-${postType.name}`, + label: __('Add New', 'secure-custom-fields') + ` ${singularLabel}`, + url: `${adminUrl}post-new.php?post_type=${postType.name}`, + icon: 'plus', + description: __('SCF: Create a new', 'secure-custom-fields') + ` ${singularLabel}`, + keywords: ['add', 'new', 'create', 'content', postType.name, postType.label || ''] + }); }); - + } + + // Register each command + commands.forEach(command => { commandStore.registerCommand({ - name: `scf-new-${postType.name}`, - label: wp.i18n.__(`New ${postType.singular_label}`, 'secure-custom-fields'), + name: 'scf/' + command.name, + label: command.label, + icon: createElement(Icon, { icon: command.icon }), + context: 'admin', + description: command.description, + keywords: command.keywords, callback: () => { - window.location.href = `${adminUrl}post-new.php?post_type=${postType.name}`; - }, - group: 'secure-custom-fields', + window.location.href = command.url; + } }); }); -} - -// Register commands when DOM is ready -wp.domReady(registerSCFCommands); \ No newline at end of file +}); \ No newline at end of file diff --git a/secure-custom-fields.php b/secure-custom-fields.php index bbd7287a..cc9d99f4 100644 --- a/secure-custom-fields.php +++ b/secure-custom-fields.php @@ -245,6 +245,11 @@ public function load_command_palette() { return; } + // Dependencies are automatically loaded by WordPress + // since they're specified in the script registration + + // Script is already registered in assets.php + // Get all SCF custom post types to add to command palette $custom_post_types = array(); @@ -268,44 +273,20 @@ public function load_command_palette() { } } - // Enqueue necessary WordPress dependencies for the command palette - wp_enqueue_script( 'wp-plugins' ); - wp_enqueue_script( 'wp-element' ); - wp_enqueue_script( 'wp-components' ); - wp_enqueue_script( 'wp-data' ); - wp_enqueue_script( 'wp-commands' ); - wp_enqueue_script( 'wp-i18n' ); - wp_enqueue_script( 'wp-dom-ready' ); - - // Register and enqueue our command palette script - $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; - $version = acf_get_setting( 'version' ); - - // First deregister the script if it was registered before - wp_deregister_script( 'acf-command-palette' ); - - wp_register_script( - 'acf-command-palette', - acf_get_setting( 'url' ) . "assets/build/js/acf-command-palette{$suffix}.js", - array( 'wp-data', 'wp-i18n', 'wp-dom-ready' ), - $version, - true - ); - - // Set up data as a property of wp object to follow WordPress conventions + // Set up data under the wp.scf namespace following WordPress best practices wp_add_inline_script( 'acf-command-palette', - 'window.wp = window.wp || {}; wp.scf = ' . wp_json_encode( + 'window.wp = window.wp || {}; window.wp.scf = window.wp.scf || {}; window.wp.scf.commands = ' . wp_json_encode( array( - 'commandData' => array( - 'customPostTypes' => $custom_post_types, - 'adminUrl' => admin_url(), - ), + 'postTypes' => $custom_post_types, + 'adminUrl' => admin_url(), ) ) . ';', 'before' ); + // Enqueue the command palette script which was registered in assets.php + // The script uses the WordPress plugins API to properly integrate with the command palette wp_enqueue_script( 'acf-command-palette' ); } From 6fce2a9238c12030f3605e14ca748a16e63b6c3f Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Fri, 18 Apr 2025 17:26:49 +0200 Subject: [PATCH 07/33] Refactor to pass the data in acf.data.customPostTypes --- assets/src/js/acf-command-palette.js | 6 +++--- secure-custom-fields.php | 15 +++++---------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/assets/src/js/acf-command-palette.js b/assets/src/js/acf-command-palette.js index 98af2e7d..4c8439b1 100644 --- a/assets/src/js/acf-command-palette.js +++ b/assets/src/js/acf-command-palette.js @@ -20,9 +20,9 @@ wp.domReady(() => { const { Icon } = wp.components; const commandStore = wp.data.dispatch('core/commands'); - // Get data from namespace - const adminUrl = wp.scf?.commands?.adminUrl || ''; - const postTypes = wp.scf?.commands?.postTypes || []; + // Get data from ACF object + const adminUrl = acf?.data?.admin_url || ''; + const postTypes = acf?.data?.customPostTypes || []; // Command definitions for SCF admin pages with improved metadata let commands = [ diff --git a/secure-custom-fields.php b/secure-custom-fields.php index cc9d99f4..d9cdd678 100644 --- a/secure-custom-fields.php +++ b/secure-custom-fields.php @@ -273,16 +273,11 @@ public function load_command_palette() { } } - // Set up data under the wp.scf namespace following WordPress best practices - wp_add_inline_script( - 'acf-command-palette', - 'window.wp = window.wp || {}; window.wp.scf = window.wp.scf || {}; window.wp.scf.commands = ' . wp_json_encode( - array( - 'postTypes' => $custom_post_types, - 'adminUrl' => admin_url(), - ) - ) . ';', - 'before' + // Add custom post types data to ACF object + acf_localize_data( + array( + 'customPostTypes' => $custom_post_types, + ) ); // Enqueue the command palette script which was registered in assets.php From f28d69de3572360e0f39fef27a3295d118976c6c Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Fri, 18 Apr 2025 18:49:20 +0200 Subject: [PATCH 08/33] Fix redirections --- assets/src/js/acf-command-palette.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/assets/src/js/acf-command-palette.js b/assets/src/js/acf-command-palette.js index 4c8439b1..52094c31 100644 --- a/assets/src/js/acf-command-palette.js +++ b/assets/src/js/acf-command-palette.js @@ -45,7 +45,7 @@ wp.domReady(() => { { name: 'post-types', label: __('Post Types', 'secure-custom-fields'), - url: `${adminUrl}admin.php?page=acf-post-types`, + url: `${adminUrl}edit.php?post_type=acf-post-type`, icon: 'admin-post', description: __('SCF: Manage custom post types', 'secure-custom-fields'), keywords: ['cpt', 'content types', 'manage post types'] @@ -53,7 +53,7 @@ wp.domReady(() => { { name: 'new-post-type', label: __('Create New Post Type', 'secure-custom-fields'), - url: `${adminUrl}admin.php?page=acf-post-type`, + url: `${adminUrl}post-new.php?post_type=acf-post-type`, icon: 'plus', description: __('SCF: Create a new custom post type', 'secure-custom-fields'), keywords: ['add', 'new', 'create', 'cpt', 'content type'] @@ -61,7 +61,7 @@ wp.domReady(() => { { name: 'taxonomies', label: __('Taxonomies', 'secure-custom-fields'), - url: `${adminUrl}admin.php?page=acf-taxonomies`, + url: `${adminUrl}edit.php?post_type=acf-taxonomy`, icon: 'category', description: __('SCF: Manage custom taxonomies for organizing content', 'secure-custom-fields'), keywords: ['categories', 'tags', 'terms', 'custom taxonomies'] @@ -69,7 +69,7 @@ wp.domReady(() => { { name: 'new-taxonomy', label: __('Create New Taxonomy', 'secure-custom-fields'), - url: `${adminUrl}admin.php?page=acf-taxonomy`, + url: `${adminUrl}post-new.php?post_type=acf-taxonomy`, icon: 'plus', description: __('SCF: Create a new custom taxonomy', 'secure-custom-fields'), keywords: ['add', 'new', 'create', 'taxonomy', 'categories', 'tags'] @@ -77,7 +77,7 @@ wp.domReady(() => { { name: 'options-pages', label: __('Options Pages', 'secure-custom-fields'), - url: `${adminUrl}admin.php?page=acf-options-pages`, + url: `${adminUrl}edit.php?post_type=acf-ui-options-page`, icon: 'admin-settings', description: __('SCF: Manage custom options pages for global settings', 'secure-custom-fields'), keywords: ['settings', 'global options', 'site options'] @@ -85,7 +85,7 @@ wp.domReady(() => { { name: 'new-options-page', label: __('Create New Options Page', 'secure-custom-fields'), - url: `${adminUrl}admin.php?page=acf-ui-options-page`, + url: `${adminUrl}post-new.php?post_type=acf-ui-options-page`, icon: 'plus', description: __('SCF: Create a new custom options page', 'secure-custom-fields'), keywords: ['add', 'new', 'create', 'options', 'settings page'] @@ -158,8 +158,9 @@ wp.domReady(() => { context: 'admin', description: command.description, keywords: command.keywords, - callback: () => { - window.location.href = command.url; + callback: ({ close }) => { + document.location = command.url; + close(); } }); }); From 6e4431ce8251d060165d9efbfe93dc2ac183e1dd Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Wed, 23 Apr 2025 14:34:07 +0200 Subject: [PATCH 09/33] Check capabilities before registering comands Includes a refactor to divide commands between core and post-type based: core commands require admin permissions, whereas post-types are dynamic and depend on their own capabilities. --- ...palette.js => acf-command-palette-core.js} | 50 +++---------- .../src/js/acf-command-palette-post-types.js | 73 +++++++++++++++++++ includes/assets.php | 20 ++++- secure-custom-fields.php | 36 ++++++--- webpack.config.js | 3 +- 5 files changed, 128 insertions(+), 54 deletions(-) rename assets/src/js/{acf-command-palette.js => acf-command-palette-core.js} (73%) create mode 100644 assets/src/js/acf-command-palette-post-types.js diff --git a/assets/src/js/acf-command-palette.js b/assets/src/js/acf-command-palette-core.js similarity index 73% rename from assets/src/js/acf-command-palette.js rename to assets/src/js/acf-command-palette-core.js index 52094c31..52288801 100644 --- a/assets/src/js/acf-command-palette.js +++ b/assets/src/js/acf-command-palette-core.js @@ -1,8 +1,7 @@ /** - * SCF Command Palette integration + * SCF Core Command Palette integration * - * Uses WordPress Commands API to add Secure Custom Fields commands to the WordPress command palette. - * Enhances the user experience with icons, descriptions, and keywords for better discoverability. + * Core WordPress admin commands for Secure Custom Fields. * * @since 6.5.0 */ @@ -14,6 +13,11 @@ wp.domReady(() => { return; } + // Wait for ACF to be ready + if (typeof acf === 'undefined') { + return; + } + // Access essential WordPress functions and data const { __ } = wp.i18n; const { createElement } = wp.element; @@ -22,10 +26,9 @@ wp.domReady(() => { // Get data from ACF object const adminUrl = acf?.data?.admin_url || ''; - const postTypes = acf?.data?.customPostTypes || []; - // Command definitions for SCF admin pages with improved metadata - let commands = [ + // Core command definitions for SCF admin pages + const commands = [ { name: 'field-groups', label: __('Field Groups', 'secure-custom-fields'), @@ -116,39 +119,6 @@ wp.domReady(() => { } ]; - // Add commands for user-created custom post types - if (postTypes && postTypes.length > 0) { - // Add each custom post type as a command - postTypes.forEach(postType => { - // Skip invalid post types - if (!postType?.name) return; - - // Get labels - const pluralLabel = postType.label || postType.name; - const singularLabel = postType.singular_label || pluralLabel; - - // Add command to view all posts of this type - commands.push({ - name: `cpt-${postType.name}`, - label: pluralLabel, - url: `${adminUrl}edit.php?post_type=${postType.name}`, - icon: 'admin-page', // Using standard dashicon for better visibility - description: __('SCF: View all', 'secure-custom-fields') + ` ${pluralLabel}`, - keywords: ['post type', 'content', 'cpt', postType.name, postType.label || ''] - }); - - // Also add command to add new post of this type - commands.push({ - name: `new-${postType.name}`, - label: __('Add New', 'secure-custom-fields') + ` ${singularLabel}`, - url: `${adminUrl}post-new.php?post_type=${postType.name}`, - icon: 'plus', - description: __('SCF: Create a new', 'secure-custom-fields') + ` ${singularLabel}`, - keywords: ['add', 'new', 'create', 'content', postType.name, postType.label || ''] - }); - }); - } - // Register each command commands.forEach(command => { commandStore.registerCommand({ @@ -164,4 +134,4 @@ wp.domReady(() => { } }); }); -}); \ No newline at end of file +}); \ No newline at end of file diff --git a/assets/src/js/acf-command-palette-post-types.js b/assets/src/js/acf-command-palette-post-types.js new file mode 100644 index 00000000..ad99e72d --- /dev/null +++ b/assets/src/js/acf-command-palette-post-types.js @@ -0,0 +1,73 @@ +/** + * SCF Dynamic Post Type Command Palette integration + * + * Dynamic commands for user-created custom post types in Secure Custom Fields. + * + * @since 6.5.0 + */ + +// Register commands when WordPress is ready +wp.domReady(() => { + // Make sure required WordPress dependencies are available + if (!wp.data || !wp.data.dispatch || !wp.data.dispatch('core/commands')) { + return; + } + + // Wait for ACF to be ready + if (typeof acf === 'undefined') { + return; + } + + // Access essential WordPress functions and data + const { __ } = wp.i18n; + const { createElement } = wp.element; + const { Icon } = wp.components; + const commandStore = wp.data.dispatch('core/commands'); + + // Get data from ACF object + const adminUrl = acf?.data?.admin_url || ''; + const postTypes = acf?.data?.customPostTypes || []; + + // Skip if no custom post types + if (!postTypes || postTypes.length === 0) { + return; + } + + // Add commands for each custom post type + postTypes.forEach(postType => { + // Skip invalid post types + if (!postType?.name) return; + + // Get labels + const pluralLabel = postType.label || postType.name; + const singularLabel = postType.singular_label || pluralLabel; + + // Add command to view all posts of this type + commandStore.registerCommand({ + name: `scf/cpt-${postType.name}`, + label: pluralLabel, + icon: createElement(Icon, { icon: 'admin-page' }), + context: 'admin', + description: __('SCF: View all', 'secure-custom-fields') + ` ${pluralLabel}`, + keywords: ['post type', 'content', 'cpt', postType.name, postType.label || ''], + callback: ({ close }) => { + document.location = `${adminUrl}edit.php?post_type=${postType.name}`; + close(); + } + }); + + // Add "new post" command (all included post types are editable by current user) + commandStore.registerCommand({ + name: `scf/new-${postType.name}`, + label: __('Add New', 'secure-custom-fields') + ` ${singularLabel}`, + icon: createElement(Icon, { icon: 'plus' }), + context: 'admin', + description: __('SCF: Create a new', 'secure-custom-fields') + ` ${singularLabel}`, + keywords: ['add', 'new', 'create', 'content', postType.name, postType.label || ''], + callback: ({ close }) => { + document.location = `${adminUrl}post-new.php?post_type=${postType.name}`; + close(); + } + }); + }); +}); \ No newline at end of file diff --git a/includes/assets.php b/includes/assets.php index 431da3ff..62bab4ec 100644 --- a/includes/assets.php +++ b/includes/assets.php @@ -242,13 +242,31 @@ public function register_scripts() { $script['in_footer'] ); } + + // Register core scripts wp_register_script( 'acf', acf_get_url( 'assets/build/js/acf' . $suffix . '.js' ), array( 'jquery' ), $version, false ); wp_register_script( 'acf-input', acf_get_url( 'assets/build/js/acf-input' . $suffix . '.js' ), array( 'jquery', 'jquery-ui-sortable', 'jquery-ui-resizable', 'acf', 'wp-a11y' ), $version, false ); - wp_register_script( 'acf-command-palette', acf_get_url( 'assets/build/js/acf-command-palette' . $suffix . '.js' ), array( 'acf', 'wp-plugins', 'wp-element', 'wp-components', 'wp-data', 'wp-commands', 'wp-i18n', 'wp-dom-ready' ), $version, true ); wp_register_script( 'acf-field-group', acf_get_url( 'assets/build/js/acf-field-group' . $suffix . '.js' ), array( 'acf-input' ), $version, false ); wp_register_script( 'acf-internal-post-type', acf_get_url( 'assets/build/js/acf-internal-post-type' . $suffix . '.js' ), array( 'acf-input' ), $version, false ); wp_register_script( 'acf-escaped-html-notice', acf_get_url( 'assets/build/js/acf-escaped-html-notice' . $suffix . '.js' ), array( 'jquery' ), $version, true ); + // Register command palette scripts + wp_register_script( + 'acf-command-palette-core', + acf_get_url( 'assets/build/js/acf-command-palette-core' . $suffix . '.js' ), + array( 'acf', 'wp-plugins', 'wp-element', 'wp-components', 'wp-data', 'wp-commands', 'wp-i18n', 'wp-dom-ready' ), + $version, + true + ); + + wp_register_script( + 'acf-command-palette-post-types', + acf_get_url( 'assets/build/js/acf-command-palette-post-types' . $suffix . '.js' ), + array( 'acf', 'wp-plugins', 'wp-element', 'wp-components', 'wp-data', 'wp-commands', 'wp-i18n', 'wp-dom-ready' ), + $version, + true + ); + // Register styles. foreach ( $styles as $style ) { wp_register_style( diff --git a/secure-custom-fields.php b/secure-custom-fields.php index d9cdd678..c1bcdca7 100644 --- a/secure-custom-fields.php +++ b/secure-custom-fields.php @@ -245,10 +245,10 @@ public function load_command_palette() { return; } - // Dependencies are automatically loaded by WordPress - // since they're specified in the script registration + // Check if current user has capability to access SCF admin + $user_can_admin = current_user_can( acf_get_setting( 'capability' ) ); - // Script is already registered in assets.php + // Admin capabilities required for core commands, but all users can see post type commands // Get all SCF custom post types to add to command palette $custom_post_types = array(); @@ -263,12 +263,16 @@ public function load_command_palette() { $plural_label = $post_type['labels']['name'] ?? $post_type['label'] ?? $post_type['post_type']; $singular_label = $post_type['labels']['singular_name'] ?? $post_type['singular_label'] ?? $plural_label; - $custom_post_types[] = array( - 'name' => $post_type['post_type'], - 'label' => $plural_label, - 'singular_label' => $singular_label, - 'icon' => $post_type['menu_icon'] ?? '', - ); + // Only add post types that the user has access to + $post_type_obj = get_post_type_object( $post_type['post_type'] ); + if ( $post_type_obj && current_user_can( $post_type_obj->cap->edit_posts ) ) { + $custom_post_types[] = array( + 'name' => $post_type['post_type'], + 'label' => $plural_label, + 'singular_label' => $singular_label, + 'icon' => $post_type['menu_icon'] ?? '', + ); + } } } } @@ -280,9 +284,17 @@ public function load_command_palette() { ) ); - // Enqueue the command palette script which was registered in assets.php - // The script uses the WordPress plugins API to properly integrate with the command palette - wp_enqueue_script( 'acf-command-palette' ); + // Always enqueue the core command palette + // We have at least one custom post type the user can access + if ( ! empty( $custom_post_types ) ) { + // Enqueue the post types command palette + wp_enqueue_script( 'acf-command-palette-post-types' ); + } + + // Only load admin commands if user has SCF admin capabilities + if ( $user_can_admin ) { + wp_enqueue_script( 'acf-command-palette-core' ); + } } /** diff --git a/webpack.config.js b/webpack.config.js index 81f74eac..e699f294 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -15,7 +15,8 @@ const commonConfig = { 'js/acf-input': './assets/src/js/acf-input.js', 'js/acf-internal-post-type': './assets/src/js/acf-internal-post-type.js', - 'js/acf-command-palette': './assets/src/js/acf-command-palette.js', + 'js/acf-command-palette-core': './assets/src/js/acf-command-palette-core.js', + 'js/acf-command-palette-post-types': './assets/src/js/acf-command-palette-post-types.js', 'js/acf': './assets/src/js/acf.js', 'js/pro/acf-pro-blocks': './assets/src/js/pro/acf-pro-blocks.js', 'js/pro/acf-pro-field-group': From 65485ac14623efa0459da69ec4b546d7641248bd Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Wed, 23 Apr 2025 16:50:31 +0200 Subject: [PATCH 10/33] Filter post types that don't enable the setting "show in UI" --- secure-custom-fields.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/secure-custom-fields.php b/secure-custom-fields.php index c1bcdca7..77cf2b22 100644 --- a/secure-custom-fields.php +++ b/secure-custom-fields.php @@ -265,7 +265,13 @@ public function load_command_palette() { // Only add post types that the user has access to $post_type_obj = get_post_type_object( $post_type['post_type'] ); - if ( $post_type_obj && current_user_can( $post_type_obj->cap->edit_posts ) ) { + // Three conditions must be met to include this post type in the command palette: + // 1. Post type object must exist + // 2. Current user must have permission to edit posts of this type + // 3. Post type must have admin UI enabled (show_ui setting) + if ( $post_type_obj && + current_user_can( $post_type_obj->cap->edit_posts ) && + $post_type_obj->show_ui ) { $custom_post_types[] = array( 'name' => $post_type['post_type'], 'label' => $plural_label, From b06b8a7d8aebb18870f982fdf9f9dfa6816f8cbd Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Wed, 23 Apr 2025 18:49:50 +0200 Subject: [PATCH 11/33] Redo webpack config linting --- webpack.config.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/webpack.config.js b/webpack.config.js index e699f294..62d2cdcb 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -82,11 +82,11 @@ const unminifiedConfig = { new RemoveEmptyScriptsPlugin(), new MiniCssExtractPlugin( { filename: '[name].css', // Output CSS as .css - }), - new DependencyExtractionWebpackPlugin({ + } ), + new DependencyExtractionWebpackPlugin( { injectPolyfill: true, useCombinedAssetFile: true, - }), + } ), ], }; @@ -116,11 +116,11 @@ const minifiedConfig = { new RemoveEmptyScriptsPlugin(), new MiniCssExtractPlugin( { filename: '[name].min.css', // Changed to output .min.css files - }), - new DependencyExtractionWebpackPlugin({ + } ), + new DependencyExtractionWebpackPlugin( { injectPolyfill: true, useCombinedAssetFile: true, - }), + } ), ], }; From f5a6cba98c7e91ec0559c4872ae1ff5ff2197af0 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Wed, 23 Apr 2025 18:50:06 +0200 Subject: [PATCH 12/33] Redo webpack linting --- webpack.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpack.config.js b/webpack.config.js index 62d2cdcb..3f50cc4b 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -45,7 +45,7 @@ const commonConfig = { use: { loader: 'babel-loader', options: { - presets: ['@babel/preset-react'], + presets: [ '@babel/preset-react' ], }, }, }, From 4c6f5da4b548c16dd0ac9dcce16a35345ba30c07 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Thu, 24 Apr 2025 14:50:02 +0200 Subject: [PATCH 13/33] Apply linting --- assets/src/js/acf-command-palette-core.js | 219 +++++++++++------- .../src/js/acf-command-palette-post-types.js | 88 ++++--- 2 files changed, 192 insertions(+), 115 deletions(-) diff --git a/assets/src/js/acf-command-palette-core.js b/assets/src/js/acf-command-palette-core.js index 52288801..24d29091 100644 --- a/assets/src/js/acf-command-palette-core.js +++ b/assets/src/js/acf-command-palette-core.js @@ -2,19 +2,23 @@ * SCF Core Command Palette integration * * Core WordPress admin commands for Secure Custom Fields. - * + * * @since 6.5.0 */ // Register commands when WordPress is ready -wp.domReady(() => { +wp.domReady( () => { // Make sure required WordPress dependencies are available - if (!wp.data || !wp.data.dispatch || !wp.data.dispatch('core/commands')) { + if ( + ! wp.data || + ! wp.data.dispatch || + ! wp.data.dispatch( 'core/commands' ) + ) { return; } // Wait for ACF to be ready - if (typeof acf === 'undefined') { + if ( typeof acf === 'undefined' ) { return; } @@ -22,116 +26,167 @@ wp.domReady(() => { const { __ } = wp.i18n; const { createElement } = wp.element; const { Icon } = wp.components; - const commandStore = wp.data.dispatch('core/commands'); - + const commandStore = wp.data.dispatch( 'core/commands' ); + // Get data from ACF object const adminUrl = acf?.data?.admin_url || ''; // Core command definitions for SCF admin pages const commands = [ - { - name: 'field-groups', - label: __('Field Groups', 'secure-custom-fields'), - url: `${adminUrl}edit.php?post_type=acf-field-group`, + { + name: 'field-groups', + label: __( 'Field Groups', 'secure-custom-fields' ), + url: `${ adminUrl }edit.php?post_type=acf-field-group`, icon: 'layout', - description: __('SCF: View and manage custom field groups', 'secure-custom-fields'), - keywords: ['acf', 'custom fields', 'field editor', 'manage fields'] + description: __( + 'SCF: View and manage custom field groups', + 'secure-custom-fields' + ), + keywords: [ + 'acf', + 'custom fields', + 'field editor', + 'manage fields', + ], }, - { - name: 'new-field-group', - label: __('Create New Field Group', 'secure-custom-fields'), - url: `${adminUrl}post-new.php?post_type=acf-field-group`, + { + name: 'new-field-group', + label: __( 'Create New Field Group', 'secure-custom-fields' ), + url: `${ adminUrl }post-new.php?post_type=acf-field-group`, icon: 'plus', - description: __('SCF: Create a new field group to organize custom fields', 'secure-custom-fields'), - keywords: ['add', 'new', 'create', 'field group', 'custom fields'] + description: __( + 'SCF: Create a new field group to organize custom fields', + 'secure-custom-fields' + ), + keywords: [ + 'add', + 'new', + 'create', + 'field group', + 'custom fields', + ], }, - { - name: 'post-types', - label: __('Post Types', 'secure-custom-fields'), - url: `${adminUrl}edit.php?post_type=acf-post-type`, + { + name: 'post-types', + label: __( 'Post Types', 'secure-custom-fields' ), + url: `${ adminUrl }edit.php?post_type=acf-post-type`, icon: 'admin-post', - description: __('SCF: Manage custom post types', 'secure-custom-fields'), - keywords: ['cpt', 'content types', 'manage post types'] + description: __( + 'SCF: Manage custom post types', + 'secure-custom-fields' + ), + keywords: [ 'cpt', 'content types', 'manage post types' ], }, - { - name: 'new-post-type', - label: __('Create New Post Type', 'secure-custom-fields'), - url: `${adminUrl}post-new.php?post_type=acf-post-type`, + { + name: 'new-post-type', + label: __( 'Create New Post Type', 'secure-custom-fields' ), + url: `${ adminUrl }post-new.php?post_type=acf-post-type`, icon: 'plus', - description: __('SCF: Create a new custom post type', 'secure-custom-fields'), - keywords: ['add', 'new', 'create', 'cpt', 'content type'] + description: __( + 'SCF: Create a new custom post type', + 'secure-custom-fields' + ), + keywords: [ 'add', 'new', 'create', 'cpt', 'content type' ], }, - { - name: 'taxonomies', - label: __('Taxonomies', 'secure-custom-fields'), - url: `${adminUrl}edit.php?post_type=acf-taxonomy`, + { + name: 'taxonomies', + label: __( 'Taxonomies', 'secure-custom-fields' ), + url: `${ adminUrl }edit.php?post_type=acf-taxonomy`, icon: 'category', - description: __('SCF: Manage custom taxonomies for organizing content', 'secure-custom-fields'), - keywords: ['categories', 'tags', 'terms', 'custom taxonomies'] + description: __( + 'SCF: Manage custom taxonomies for organizing content', + 'secure-custom-fields' + ), + keywords: [ 'categories', 'tags', 'terms', 'custom taxonomies' ], }, - { - name: 'new-taxonomy', - label: __('Create New Taxonomy', 'secure-custom-fields'), - url: `${adminUrl}post-new.php?post_type=acf-taxonomy`, + { + name: 'new-taxonomy', + label: __( 'Create New Taxonomy', 'secure-custom-fields' ), + url: `${ adminUrl }post-new.php?post_type=acf-taxonomy`, icon: 'plus', - description: __('SCF: Create a new custom taxonomy', 'secure-custom-fields'), - keywords: ['add', 'new', 'create', 'taxonomy', 'categories', 'tags'] + description: __( + 'SCF: Create a new custom taxonomy', + 'secure-custom-fields' + ), + keywords: [ + 'add', + 'new', + 'create', + 'taxonomy', + 'categories', + 'tags', + ], }, - { - name: 'options-pages', - label: __('Options Pages', 'secure-custom-fields'), - url: `${adminUrl}edit.php?post_type=acf-ui-options-page`, + { + name: 'options-pages', + label: __( 'Options Pages', 'secure-custom-fields' ), + url: `${ adminUrl }edit.php?post_type=acf-ui-options-page`, icon: 'admin-settings', - description: __('SCF: Manage custom options pages for global settings', 'secure-custom-fields'), - keywords: ['settings', 'global options', 'site options'] + description: __( + 'SCF: Manage custom options pages for global settings', + 'secure-custom-fields' + ), + keywords: [ 'settings', 'global options', 'site options' ], }, - { - name: 'new-options-page', - label: __('Create New Options Page', 'secure-custom-fields'), - url: `${adminUrl}post-new.php?post_type=acf-ui-options-page`, + { + name: 'new-options-page', + label: __( 'Create New Options Page', 'secure-custom-fields' ), + url: `${ adminUrl }post-new.php?post_type=acf-ui-options-page`, icon: 'plus', - description: __('SCF: Create a new custom options page', 'secure-custom-fields'), - keywords: ['add', 'new', 'create', 'options', 'settings page'] + description: __( + 'SCF: Create a new custom options page', + 'secure-custom-fields' + ), + keywords: [ 'add', 'new', 'create', 'options', 'settings page' ], }, - { - name: 'tools', - label: __('SCF Tools', 'secure-custom-fields'), - url: `${adminUrl}admin.php?page=acf-tools`, + { + name: 'tools', + label: __( 'SCF Tools', 'secure-custom-fields' ), + url: `${ adminUrl }admin.php?page=acf-tools`, icon: 'admin-tools', - description: __('SCF: Access SCF utility tools', 'secure-custom-fields'), - keywords: ['utilities', 'import export', 'json'] + description: __( + 'SCF: Access SCF utility tools', + 'secure-custom-fields' + ), + keywords: [ 'utilities', 'import export', 'json' ], }, - { - name: 'import', - label: __('Import SCF Data', 'secure-custom-fields'), - url: `${adminUrl}admin.php?page=acf-tools&tool=import`, + { + name: 'import', + label: __( 'Import SCF Data', 'secure-custom-fields' ), + url: `${ adminUrl }admin.php?page=acf-tools&tool=import`, icon: 'upload', - description: __('SCF: Import field groups, post types, taxonomies, and options pages', 'secure-custom-fields'), - keywords: ['upload', 'json', 'migration', 'transfer'] + description: __( + 'SCF: Import field groups, post types, taxonomies, and options pages', + 'secure-custom-fields' + ), + keywords: [ 'upload', 'json', 'migration', 'transfer' ], }, - { - name: 'export', - label: __('Export SCF Data', 'secure-custom-fields'), - url: `${adminUrl}admin.php?page=acf-tools&tool=export`, + { + name: 'export', + label: __( 'Export SCF Data', 'secure-custom-fields' ), + url: `${ adminUrl }admin.php?page=acf-tools&tool=export`, icon: 'download', - description: __('SCF: Export field groups, post types, taxonomies, and options pages', 'secure-custom-fields'), - keywords: ['download', 'json', 'backup', 'migration'] - } + description: __( + 'SCF: Export field groups, post types, taxonomies, and options pages', + 'secure-custom-fields' + ), + keywords: [ 'download', 'json', 'backup', 'migration' ], + }, ]; - + // Register each command - commands.forEach(command => { - commandStore.registerCommand({ + commands.forEach( ( command ) => { + commandStore.registerCommand( { name: 'scf/' + command.name, label: command.label, - icon: createElement(Icon, { icon: command.icon }), + icon: createElement( Icon, { icon: command.icon } ), context: 'admin', description: command.description, keywords: command.keywords, - callback: ({ close }) => { + callback: ( { close } ) => { document.location = command.url; close(); - } - }); - }); -}); \ No newline at end of file + }, + } ); + } ); +} ); diff --git a/assets/src/js/acf-command-palette-post-types.js b/assets/src/js/acf-command-palette-post-types.js index ad99e72d..456aa7df 100644 --- a/assets/src/js/acf-command-palette-post-types.js +++ b/assets/src/js/acf-command-palette-post-types.js @@ -2,19 +2,23 @@ * SCF Dynamic Post Type Command Palette integration * * Dynamic commands for user-created custom post types in Secure Custom Fields. - * + * * @since 6.5.0 */ // Register commands when WordPress is ready -wp.domReady(() => { +wp.domReady( () => { // Make sure required WordPress dependencies are available - if (!wp.data || !wp.data.dispatch || !wp.data.dispatch('core/commands')) { + if ( + ! wp.data || + ! wp.data.dispatch || + ! wp.data.dispatch( 'core/commands' ) + ) { return; } // Wait for ACF to be ready - if (typeof acf === 'undefined') { + if ( typeof acf === 'undefined' ) { return; } @@ -22,52 +26,70 @@ wp.domReady(() => { const { __ } = wp.i18n; const { createElement } = wp.element; const { Icon } = wp.components; - const commandStore = wp.data.dispatch('core/commands'); - + const commandStore = wp.data.dispatch( 'core/commands' ); + // Get data from ACF object const adminUrl = acf?.data?.admin_url || ''; const postTypes = acf?.data?.customPostTypes || []; // Skip if no custom post types - if (!postTypes || postTypes.length === 0) { + if ( ! postTypes || postTypes.length === 0 ) { return; } // Add commands for each custom post type - postTypes.forEach(postType => { + postTypes.forEach( ( postType ) => { // Skip invalid post types - if (!postType?.name) return; - + if ( ! postType?.name ) return; + // Get labels const pluralLabel = postType.label || postType.name; const singularLabel = postType.singular_label || pluralLabel; - + // Add command to view all posts of this type - commandStore.registerCommand({ - name: `scf/cpt-${postType.name}`, + commandStore.registerCommand( { + name: `scf/cpt-${ postType.name }`, label: pluralLabel, - icon: createElement(Icon, { icon: 'admin-page' }), + icon: createElement( Icon, { icon: 'admin-page' } ), context: 'admin', - description: __('SCF: View all', 'secure-custom-fields') + ` ${pluralLabel}`, - keywords: ['post type', 'content', 'cpt', postType.name, postType.label || ''], - callback: ({ close }) => { - document.location = `${adminUrl}edit.php?post_type=${postType.name}`; + description: + __( 'SCF: View all', 'secure-custom-fields' ) + + ` ${ pluralLabel }`, + keywords: [ + 'post type', + 'content', + 'cpt', + postType.name, + postType.label || '', + ], + callback: ( { close } ) => { + document.location = `${ adminUrl }edit.php?post_type=${ postType.name }`; close(); - } - }); - + }, + } ); + // Add "new post" command (all included post types are editable by current user) - commandStore.registerCommand({ - name: `scf/new-${postType.name}`, - label: __('Add New', 'secure-custom-fields') + ` ${singularLabel}`, - icon: createElement(Icon, { icon: 'plus' }), + commandStore.registerCommand( { + name: `scf/new-${ postType.name }`, + label: + __( 'Add New', 'secure-custom-fields' ) + ` ${ singularLabel }`, + icon: createElement( Icon, { icon: 'plus' } ), context: 'admin', - description: __('SCF: Create a new', 'secure-custom-fields') + ` ${singularLabel}`, - keywords: ['add', 'new', 'create', 'content', postType.name, postType.label || ''], - callback: ({ close }) => { - document.location = `${adminUrl}post-new.php?post_type=${postType.name}`; + description: + __( 'SCF: Create a new', 'secure-custom-fields' ) + + ` ${ singularLabel }`, + keywords: [ + 'add', + 'new', + 'create', + 'content', + postType.name, + postType.label || '', + ], + callback: ( { close } ) => { + document.location = `${ adminUrl }post-new.php?post_type=${ postType.name }`; close(); - } - }); - }); -}); \ No newline at end of file + }, + } ); + } ); +} ); From c592bebe5831e4ee5f7df2f3eb3a1611b0e7f7bf Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Thu, 24 Apr 2025 15:12:40 +0200 Subject: [PATCH 14/33] Polish --- assets/src/js/acf-command-palette-core.js | 7 +--- .../src/js/acf-command-palette-post-types.js | 42 ++++++++++++------- debug-command-palette.js | 1 - secure-custom-fields.php | 17 +++++--- 4 files changed, 40 insertions(+), 27 deletions(-) delete mode 100644 debug-command-palette.js diff --git a/assets/src/js/acf-command-palette-core.js b/assets/src/js/acf-command-palette-core.js index 24d29091..239f37c9 100644 --- a/assets/src/js/acf-command-palette-core.js +++ b/assets/src/js/acf-command-palette-core.js @@ -2,11 +2,12 @@ * SCF Core Command Palette integration * * Core WordPress admin commands for Secure Custom Fields. + * This file registers static commands for all primary SCF admin pages, + * enabling quick navigation through the command palette (Cmd+K / Ctrl+K). * * @since 6.5.0 */ -// Register commands when WordPress is ready wp.domReady( () => { // Make sure required WordPress dependencies are available if ( @@ -22,16 +23,13 @@ wp.domReady( () => { return; } - // Access essential WordPress functions and data const { __ } = wp.i18n; const { createElement } = wp.element; const { Icon } = wp.components; const commandStore = wp.data.dispatch( 'core/commands' ); - // Get data from ACF object const adminUrl = acf?.data?.admin_url || ''; - // Core command definitions for SCF admin pages const commands = [ { name: 'field-groups', @@ -174,7 +172,6 @@ wp.domReady( () => { }, ]; - // Register each command commands.forEach( ( command ) => { commandStore.registerCommand( { name: 'scf/' + command.name, diff --git a/assets/src/js/acf-command-palette-post-types.js b/assets/src/js/acf-command-palette-post-types.js index 456aa7df..e231f63c 100644 --- a/assets/src/js/acf-command-palette-post-types.js +++ b/assets/src/js/acf-command-palette-post-types.js @@ -2,11 +2,15 @@ * SCF Dynamic Post Type Command Palette integration * * Dynamic commands for user-created custom post types in Secure Custom Fields. + * This file generates commands for each registered post type that the current user + * has access to, creating both "View All" and "Add New" commands for each type. + * + * Post type data is provided via acf.data.customPostTypes, which is populated + * by the PHP side after capability checks ensure the user has appropriate access. * * @since 6.5.0 */ -// Register commands when WordPress is ready wp.domReady( () => { // Make sure required WordPress dependencies are available if ( @@ -22,13 +26,11 @@ wp.domReady( () => { return; } - // Access essential WordPress functions and data - const { __ } = wp.i18n; + const { __, sprintf } = wp.i18n; const { createElement } = wp.element; const { Icon } = wp.components; const commandStore = wp.data.dispatch( 'core/commands' ); - // Get data from ACF object const adminUrl = acf?.data?.admin_url || ''; const postTypes = acf?.data?.customPostTypes || []; @@ -37,24 +39,24 @@ wp.domReady( () => { return; } - // Add commands for each custom post type postTypes.forEach( ( postType ) => { // Skip invalid post types if ( ! postType?.name ) return; - // Get labels const pluralLabel = postType.label || postType.name; const singularLabel = postType.singular_label || pluralLabel; - // Add command to view all posts of this type commandStore.registerCommand( { name: `scf/cpt-${ postType.name }`, label: pluralLabel, icon: createElement( Icon, { icon: 'admin-page' } ), context: 'admin', description: - __( 'SCF: View all', 'secure-custom-fields' ) + - ` ${ pluralLabel }`, + /* translators: %s: Post type plural label */ + sprintf( + __( 'SCF: View all %s', 'secure-custom-fields' ), + pluralLabel + ), keywords: [ 'post type', 'content', @@ -63,21 +65,29 @@ wp.domReady( () => { postType.label || '', ], callback: ( { close } ) => { - document.location = `${ adminUrl }edit.php?post_type=${ postType.name }`; + document.location = `${ adminUrl }edit.php?post_type=${ encodeURIComponent( + postType.name + ) }`; close(); }, } ); - // Add "new post" command (all included post types are editable by current user) commandStore.registerCommand( { name: `scf/new-${ postType.name }`, label: - __( 'Add New', 'secure-custom-fields' ) + ` ${ singularLabel }`, + /* translators: %s: Post type singular label */ + sprintf( + __( 'Add New %s', 'secure-custom-fields' ), + singularLabel + ), icon: createElement( Icon, { icon: 'plus' } ), context: 'admin', description: - __( 'SCF: Create a new', 'secure-custom-fields' ) + - ` ${ singularLabel }`, + /* translators: %s: Post type singular label */ + sprintf( + __( 'SCF: Create a new %s', 'secure-custom-fields' ), + singularLabel + ), keywords: [ 'add', 'new', @@ -87,7 +97,9 @@ wp.domReady( () => { postType.label || '', ], callback: ( { close } ) => { - document.location = `${ adminUrl }post-new.php?post_type=${ postType.name }`; + document.location = `${ adminUrl }post-new.php?post_type=${ encodeURIComponent( + postType.name + ) }`; close(); }, } ); diff --git a/debug-command-palette.js b/debug-command-palette.js deleted file mode 100644 index a49fdc23..00000000 --- a/debug-command-palette.js +++ /dev/null @@ -1 +0,0 @@ -console.log('SCF Command Palette Data:', window.scfCommandPaletteData); diff --git a/secure-custom-fields.php b/secure-custom-fields.php index 77cf2b22..bd04e356 100644 --- a/secure-custom-fields.php +++ b/secure-custom-fields.php @@ -237,6 +237,17 @@ public function initialize() { /** * Loads the command palette script and its dependencies * + * This method handles the integration with WordPress Command Palette (Cmd+K / Ctrl+K), + * providing navigation commands for SCF admin pages and custom post types. + * + * The implementation follows these principles: + * 1. Only loads in admin screens + * 2. Performs capability checks to ensure users only see commands they can access + * 3. Core administrative commands are only shown to users with SCF admin capabilities + * 4. Custom post type commands are conditionally shown based on edit_posts capability + * for each specific post type + * 5. Post types must have UI enabled (show_ui setting) to appear in the command palette + * * @since 6.5.0 */ public function load_command_palette() { @@ -250,10 +261,8 @@ public function load_command_palette() { // Admin capabilities required for core commands, but all users can see post type commands - // Get all SCF custom post types to add to command palette $custom_post_types = array(); - // Get SCF post type definitions if ( function_exists( 'acf_get_acf_post_types' ) ) { $scf_post_types = acf_get_acf_post_types(); @@ -283,17 +292,13 @@ public function load_command_palette() { } } - // Add custom post types data to ACF object acf_localize_data( array( 'customPostTypes' => $custom_post_types, ) ); - // Always enqueue the core command palette - // We have at least one custom post type the user can access if ( ! empty( $custom_post_types ) ) { - // Enqueue the post types command palette wp_enqueue_script( 'acf-command-palette-post-types' ); } From 3907d63ec1eed22f17cee6cb1a0892af6b738db1 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Thu, 24 Apr 2025 15:30:25 +0200 Subject: [PATCH 15/33] Refactor --- includes/admin/admin-command-palette.php | 84 ++++++++++++++++++++++++ secure-custom-fields.php | 77 +--------------------- 2 files changed, 85 insertions(+), 76 deletions(-) create mode 100644 includes/admin/admin-command-palette.php diff --git a/includes/admin/admin-command-palette.php b/includes/admin/admin-command-palette.php new file mode 100644 index 00000000..53174657 --- /dev/null +++ b/includes/admin/admin-command-palette.php @@ -0,0 +1,84 @@ +cap->edit_posts ) && + $post_type_obj->show_ui ) { + $custom_post_types[] = array( + 'name' => $post_type['post_type'], + 'label' => $plural_label, + 'singular_label' => $singular_label, + 'icon' => $post_type['menu_icon'] ?? '', + ); + } + } + } + + acf_localize_data( + array( + 'customPostTypes' => $custom_post_types, + ) + ); + + if ( ! empty( $custom_post_types ) ) { + wp_enqueue_script( 'acf-command-palette-post-types' ); + } + + // Only load admin commands if user has SCF admin capabilities + if ( current_user_can( acf_get_setting( 'capability' ) ) ) { + wp_enqueue_script( 'acf-command-palette-core' ); + } +} + +add_action( 'admin_enqueue_scripts', 'acf_command_palette_init' ); diff --git a/secure-custom-fields.php b/secure-custom-fields.php index bd04e356..f8d3c066 100644 --- a/secure-custom-fields.php +++ b/secure-custom-fields.php @@ -213,6 +213,7 @@ public function initialize() { acf_include( 'includes/admin/admin-notices.php' ); acf_include( 'includes/admin/admin-tools.php' ); acf_include( 'includes/admin/admin-upgrade.php' ); + acf_include( 'includes/admin/admin-command-palette.php' ); acf_include( 'includes/admin/class-acf-admin-options-page.php' ); } @@ -229,84 +230,8 @@ public function initialize() { // Add filters. add_filter( 'posts_where', array( $this, 'posts_where' ), 10, 2 ); - - // Load command palette - add_action( 'admin_enqueue_scripts', array( $this, 'load_command_palette' ) ); } - /** - * Loads the command palette script and its dependencies - * - * This method handles the integration with WordPress Command Palette (Cmd+K / Ctrl+K), - * providing navigation commands for SCF admin pages and custom post types. - * - * The implementation follows these principles: - * 1. Only loads in admin screens - * 2. Performs capability checks to ensure users only see commands they can access - * 3. Core administrative commands are only shown to users with SCF admin capabilities - * 4. Custom post type commands are conditionally shown based on edit_posts capability - * for each specific post type - * 5. Post types must have UI enabled (show_ui setting) to appear in the command palette - * - * @since 6.5.0 - */ - public function load_command_palette() { - // Only load on admin screens - if ( ! is_admin() ) { - return; - } - - // Check if current user has capability to access SCF admin - $user_can_admin = current_user_can( acf_get_setting( 'capability' ) ); - - // Admin capabilities required for core commands, but all users can see post type commands - - $custom_post_types = array(); - - if ( function_exists( 'acf_get_acf_post_types' ) ) { - $scf_post_types = acf_get_acf_post_types(); - - foreach ( $scf_post_types as $post_type ) { - if ( isset( $post_type['post_type'] ) && isset( $post_type['active'] ) && $post_type['active'] ) { - // Get both plural and singular labels using null coalescing operator - $plural_label = $post_type['labels']['name'] ?? $post_type['label'] ?? $post_type['post_type']; - $singular_label = $post_type['labels']['singular_name'] ?? $post_type['singular_label'] ?? $plural_label; - - // Only add post types that the user has access to - $post_type_obj = get_post_type_object( $post_type['post_type'] ); - // Three conditions must be met to include this post type in the command palette: - // 1. Post type object must exist - // 2. Current user must have permission to edit posts of this type - // 3. Post type must have admin UI enabled (show_ui setting) - if ( $post_type_obj && - current_user_can( $post_type_obj->cap->edit_posts ) && - $post_type_obj->show_ui ) { - $custom_post_types[] = array( - 'name' => $post_type['post_type'], - 'label' => $plural_label, - 'singular_label' => $singular_label, - 'icon' => $post_type['menu_icon'] ?? '', - ); - } - } - } - } - - acf_localize_data( - array( - 'customPostTypes' => $custom_post_types, - ) - ); - - if ( ! empty( $custom_post_types ) ) { - wp_enqueue_script( 'acf-command-palette-post-types' ); - } - - // Only load admin commands if user has SCF admin capabilities - if ( $user_can_admin ) { - wp_enqueue_script( 'acf-command-palette-core' ); - } - } /** * Completes the setup process on "init" of earlier. From 60b81847cc586e5a67b05078d9797bff1f155832 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Thu, 24 Apr 2025 15:44:54 +0200 Subject: [PATCH 16/33] Fix coding standards in comments --- includes/admin/admin-command-palette.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/includes/admin/admin-command-palette.php b/includes/admin/admin-command-palette.php index 53174657..2a309181 100644 --- a/includes/admin/admin-command-palette.php +++ b/includes/admin/admin-command-palette.php @@ -26,7 +26,7 @@ * @since 6.5.0 */ function acf_command_palette_init() { - // Only load on admin screens + // Only load on admin screens. if ( ! is_admin() ) { return; } @@ -42,7 +42,6 @@ function acf_command_palette_init() { continue; } - // Get post type labels $plural_label = $post_type['labels']['name'] ?? $post_type['label'] ?? $post_type['post_type']; $singular_label = $post_type['labels']['singular_name'] ?? $post_type['singular_label'] ?? $plural_label; @@ -50,8 +49,8 @@ function acf_command_palette_init() { // Three conditions must be met to include this post type in the command palette: // 1. Post type object must exist - // 2. Current user must have permission to edit posts of this type - // 3. Post type must have admin UI enabled (show_ui setting) + // 2. Current user must have permission to edit posts of this type. + // 3. Post type must have admin UI enabled (show_ui setting). if ( $post_type_obj && current_user_can( $post_type_obj->cap->edit_posts ) && $post_type_obj->show_ui ) { @@ -75,7 +74,7 @@ function acf_command_palette_init() { wp_enqueue_script( 'acf-command-palette-post-types' ); } - // Only load admin commands if user has SCF admin capabilities + // Only load admin commands if user has SCF admin capabilities. if ( current_user_can( acf_get_setting( 'capability' ) ) ) { wp_enqueue_script( 'acf-command-palette-core' ); } From af46e4aee51d752b5b229f12c4aab37ec0376865 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Thu, 24 Apr 2025 15:50:22 +0200 Subject: [PATCH 17/33] Ensure we only register the commands when the palette is available --- assets/src/js/acf-command-palette-core.js | 4 +++- .../src/js/acf-command-palette-post-types.js | 4 +++- includes/admin/admin-command-palette.php | 19 ++++++++++++------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/assets/src/js/acf-command-palette-core.js b/assets/src/js/acf-command-palette-core.js index 239f37c9..c3e35740 100644 --- a/assets/src/js/acf-command-palette-core.js +++ b/assets/src/js/acf-command-palette-core.js @@ -10,10 +10,12 @@ wp.domReady( () => { // Make sure required WordPress dependencies are available + // This ensures we only register commands where the command palette is supported if ( ! wp.data || ! wp.data.dispatch || - ! wp.data.dispatch( 'core/commands' ) + ! wp.data.dispatch( 'core/commands' ) || + typeof wp.commands === 'undefined' ) { return; } diff --git a/assets/src/js/acf-command-palette-post-types.js b/assets/src/js/acf-command-palette-post-types.js index e231f63c..3bf5e36d 100644 --- a/assets/src/js/acf-command-palette-post-types.js +++ b/assets/src/js/acf-command-palette-post-types.js @@ -13,10 +13,12 @@ wp.domReady( () => { // Make sure required WordPress dependencies are available + // This ensures we only register commands where the command palette is supported if ( ! wp.data || ! wp.data.dispatch || - ! wp.data.dispatch( 'core/commands' ) + ! wp.data.dispatch( 'core/commands' ) || + typeof wp.commands === 'undefined' ) { return; } diff --git a/includes/admin/admin-command-palette.php b/includes/admin/admin-command-palette.php index 2a309181..30b0ef76 100644 --- a/includes/admin/admin-command-palette.php +++ b/includes/admin/admin-command-palette.php @@ -16,12 +16,12 @@ * providing navigation commands for SCF admin pages and custom post types. * * The implementation follows these principles: - * 1. Only loads in admin screens - * 2. Performs capability checks to ensure users only see commands they can access - * 3. Core administrative commands are only shown to users with SCF admin capabilities - * 4. Custom post type commands are conditionally shown based on edit_posts capability - * for each specific post type - * 5. Post types must have UI enabled (show_ui setting) to appear in the command palette + * 1. Only loads in screens where command palette is available. + * 2. Performs capability checks to ensure users only see commands they can access. + * 3. Core administrative commands are only shown to users with SCF admin capabilities. + * 4. Custom post type commands are conditionally shown based on edit_posts capability. + * for each specific post type. + * 5. Post types must have UI enabled (show_ui setting) to appear in the command palette. * * @since 6.5.0 */ @@ -31,13 +31,18 @@ function acf_command_palette_init() { return; } + // Ensure we only load our commands where the palette is available. + if ( ! wp_script_is( 'wp-commands', 'registered' ) ) { + return; + } + $custom_post_types = array(); if ( function_exists( 'acf_get_acf_post_types' ) ) { $scf_post_types = acf_get_acf_post_types(); foreach ( $scf_post_types as $post_type ) { - // Skip if post type name is not set (in theory it should always be) or post type is inactive. + // Skip if post type name is not set (in theory it should always be, defensive) or post type is inactive. if ( empty( $post_type['post_type'] ) || ( isset( $post_type['active'] ) && ! $post_type['active'] ) ) { continue; } From b2d95ab342aa048eecd9fa759c34c401ce196616 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Thu, 24 Apr 2025 18:07:34 +0200 Subject: [PATCH 18/33] Refactor to remove scf and acf prefixes, organizing files in folders similar to modules --- .../admin-commands.js} | 14 +++++----- .../custom-post-type-commands.js} | 16 +++++++----- ...command-palette.php => admin-commands.php} | 26 +++++++++---------- includes/assets.php | 12 ++++----- secure-custom-fields.php | 2 +- webpack.config.js | 4 +-- 6 files changed, 38 insertions(+), 36 deletions(-) rename assets/src/js/{acf-command-palette-core.js => commands/admin-commands.js} (92%) rename assets/src/js/{acf-command-palette-post-types.js => commands/custom-post-type-commands.js} (84%) rename includes/admin/{admin-command-palette.php => admin-commands.php} (75%) diff --git a/assets/src/js/acf-command-palette-core.js b/assets/src/js/commands/admin-commands.js similarity index 92% rename from assets/src/js/acf-command-palette-core.js rename to assets/src/js/commands/admin-commands.js index c3e35740..01458a50 100644 --- a/assets/src/js/acf-command-palette-core.js +++ b/assets/src/js/commands/admin-commands.js @@ -1,16 +1,16 @@ /** - * SCF Core Command Palette integration + * SCF Admin Commands * - * Core WordPress admin commands for Secure Custom Fields. - * This file registers static commands for all primary SCF admin pages, - * enabling quick navigation through the command palette (Cmd+K / Ctrl+K). + * Core WordPress commands for Secure Custom Fields administration. + * This file registers navigation commands for all primary SCF admin screens, + * enabling quick access through the WordPress commands interface (Cmd+K / Ctrl+K). * * @since 6.5.0 */ wp.domReady( () => { // Make sure required WordPress dependencies are available - // This ensures we only register commands where the command palette is supported + // This ensures we only register commands where the commands API is supported if ( ! wp.data || ! wp.data.dispatch || @@ -176,7 +176,7 @@ wp.domReady( () => { commands.forEach( ( command ) => { commandStore.registerCommand( { - name: 'scf/' + command.name, + name: 'acf/' + command.name, label: command.label, icon: createElement( Icon, { icon: command.icon } ), context: 'admin', @@ -188,4 +188,4 @@ wp.domReady( () => { }, } ); } ); -} ); +} ); \ No newline at end of file diff --git a/assets/src/js/acf-command-palette-post-types.js b/assets/src/js/commands/custom-post-type-commands.js similarity index 84% rename from assets/src/js/acf-command-palette-post-types.js rename to assets/src/js/commands/custom-post-type-commands.js index 3bf5e36d..2a72405a 100644 --- a/assets/src/js/acf-command-palette-post-types.js +++ b/assets/src/js/commands/custom-post-type-commands.js @@ -1,9 +1,9 @@ /** - * SCF Dynamic Post Type Command Palette integration + * SCF Post Type Commands * * Dynamic commands for user-created custom post types in Secure Custom Fields. - * This file generates commands for each registered post type that the current user - * has access to, creating both "View All" and "Add New" commands for each type. + * This file generates navigation commands for each registered post type that + * the current user has access to, creating both "View All" and "Add New" commands. * * Post type data is provided via acf.data.customPostTypes, which is populated * by the PHP side after capability checks ensure the user has appropriate access. @@ -13,7 +13,7 @@ wp.domReady( () => { // Make sure required WordPress dependencies are available - // This ensures we only register commands where the command palette is supported + // This ensures we only register commands where the commands API is supported if ( ! wp.data || ! wp.data.dispatch || @@ -48,8 +48,9 @@ wp.domReady( () => { const pluralLabel = postType.label || postType.name; const singularLabel = postType.singular_label || pluralLabel; + // Register "View All" command for this post type commandStore.registerCommand( { - name: `scf/cpt-${ postType.name }`, + name: `acf/cpt-${ postType.name }`, label: pluralLabel, icon: createElement( Icon, { icon: 'admin-page' } ), context: 'admin', @@ -74,8 +75,9 @@ wp.domReady( () => { }, } ); + // Register "Add New" command for this post type commandStore.registerCommand( { - name: `scf/new-${ postType.name }`, + name: `acf/new-${ postType.name }`, label: /* translators: %s: Post type singular label */ sprintf( @@ -106,4 +108,4 @@ wp.domReady( () => { }, } ); } ); -} ); +} ); \ No newline at end of file diff --git a/includes/admin/admin-command-palette.php b/includes/admin/admin-commands.php similarity index 75% rename from includes/admin/admin-command-palette.php rename to includes/admin/admin-commands.php index 30b0ef76..cbfd068d 100644 --- a/includes/admin/admin-command-palette.php +++ b/includes/admin/admin-commands.php @@ -1,6 +1,6 @@ enqueue_uploader(); -} +} \ No newline at end of file diff --git a/secure-custom-fields.php b/secure-custom-fields.php index f8d3c066..ebce163c 100644 --- a/secure-custom-fields.php +++ b/secure-custom-fields.php @@ -213,7 +213,7 @@ public function initialize() { acf_include( 'includes/admin/admin-notices.php' ); acf_include( 'includes/admin/admin-tools.php' ); acf_include( 'includes/admin/admin-upgrade.php' ); - acf_include( 'includes/admin/admin-command-palette.php' ); + acf_include( 'includes/admin/admin-commands.php' ); acf_include( 'includes/admin/class-acf-admin-options-page.php' ); } diff --git a/webpack.config.js b/webpack.config.js index 3f50cc4b..4ae1cb0f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -15,8 +15,8 @@ const commonConfig = { 'js/acf-input': './assets/src/js/acf-input.js', 'js/acf-internal-post-type': './assets/src/js/acf-internal-post-type.js', - 'js/acf-command-palette-core': './assets/src/js/acf-command-palette-core.js', - 'js/acf-command-palette-post-types': './assets/src/js/acf-command-palette-post-types.js', + 'js/commands/admin': './assets/src/js/commands/admin-commands.js', + 'js/commands/custom-post-types': './assets/src/js/commands/custom-post-type-commands.js', 'js/acf': './assets/src/js/acf.js', 'js/pro/acf-pro-blocks': './assets/src/js/pro/acf-pro-blocks.js', 'js/pro/acf-pro-field-group': From 101de2758a6d3a41d4aba8271a451af722d862a9 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Fri, 25 Apr 2025 12:54:50 +0200 Subject: [PATCH 19/33] Optimize return early --- assets/src/js/commands/admin-commands.js | 18 ++-------- .../js/commands/custom-post-type-commands.js | 34 ++++++------------- 2 files changed, 14 insertions(+), 38 deletions(-) diff --git a/assets/src/js/commands/admin-commands.js b/assets/src/js/commands/admin-commands.js index 01458a50..b2d70291 100644 --- a/assets/src/js/commands/admin-commands.js +++ b/assets/src/js/commands/admin-commands.js @@ -1,5 +1,5 @@ /** - * SCF Admin Commands + * Admin Commands * * Core WordPress commands for Secure Custom Fields administration. * This file registers navigation commands for all primary SCF admin screens, @@ -9,19 +9,7 @@ */ wp.domReady( () => { - // Make sure required WordPress dependencies are available - // This ensures we only register commands where the commands API is supported - if ( - ! wp.data || - ! wp.data.dispatch || - ! wp.data.dispatch( 'core/commands' ) || - typeof wp.commands === 'undefined' - ) { - return; - } - - // Wait for ACF to be ready - if ( typeof acf === 'undefined' ) { + if ( ! wp.data?.dispatch?.( 'core/commands' ) || ! acf?.data ) { return; } @@ -188,4 +176,4 @@ wp.domReady( () => { }, } ); } ); -} ); \ No newline at end of file +} ); diff --git a/assets/src/js/commands/custom-post-type-commands.js b/assets/src/js/commands/custom-post-type-commands.js index 2a72405a..ee0962d8 100644 --- a/assets/src/js/commands/custom-post-type-commands.js +++ b/assets/src/js/commands/custom-post-type-commands.js @@ -1,8 +1,8 @@ /** - * SCF Post Type Commands + * Custom Post Type Commands * * Dynamic commands for user-created custom post types in Secure Custom Fields. - * This file generates navigation commands for each registered post type that + * This file generates navigation commands for each registered post type that * the current user has access to, creating both "View All" and "Add New" commands. * * Post type data is provided via acf.data.customPostTypes, which is populated @@ -12,38 +12,26 @@ */ wp.domReady( () => { - // Make sure required WordPress dependencies are available - // This ensures we only register commands where the commands API is supported + // Only proceed when WordPress commands API and there are custom post types accessible if ( - ! wp.data || - ! wp.data.dispatch || - ! wp.data.dispatch( 'core/commands' ) || - typeof wp.commands === 'undefined' + ! wp.data?.dispatch?.( 'core/commands' ) || + ! acf?.data?.customPostTypes?.length ) { return; } - // Wait for ACF to be ready - if ( typeof acf === 'undefined' ) { - return; - } - const { __, sprintf } = wp.i18n; const { createElement } = wp.element; const { Icon } = wp.components; const commandStore = wp.data.dispatch( 'core/commands' ); - - const adminUrl = acf?.data?.admin_url || ''; - const postTypes = acf?.data?.customPostTypes || []; - - // Skip if no custom post types - if ( ! postTypes || postTypes.length === 0 ) { - return; - } + const adminUrl = acf.data.admin_url || ''; + const postTypes = acf.data.customPostTypes; postTypes.forEach( ( postType ) => { // Skip invalid post types - if ( ! postType?.name ) return; + if ( ! postType?.name ) { + return; + } const pluralLabel = postType.label || postType.name; const singularLabel = postType.singular_label || pluralLabel; @@ -108,4 +96,4 @@ wp.domReady( () => { }, } ); } ); -} ); \ No newline at end of file +} ); From 4b6a9535e8c11dcfbd53f46cf6aa1f756f211421 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Fri, 25 Apr 2025 16:51:18 +0200 Subject: [PATCH 20/33] Remove unnecessary script registration --- includes/assets.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/includes/assets.php b/includes/assets.php index 588e4d0c..0167294d 100644 --- a/includes/assets.php +++ b/includes/assets.php @@ -286,13 +286,6 @@ public function register_scripts() { * @param string $suffix The potential ".min" filename suffix. */ do_action( 'acf/register_scripts', $version, $suffix ); - - // Ensure WordPress scripts needed for command palette integration are available - if ( function_exists( 'wp_enqueue_script' ) ) { - wp_enqueue_script( 'wp-commands' ); - wp_enqueue_script( 'wp-i18n' ); - wp_enqueue_script( 'wp-dom-ready' ); - } } /** From 1a624073a3f9c8fe706e9b9d4a4a8a07c61cab47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor?= <27339341+priethor@users.noreply.github.com> Date: Fri, 25 Apr 2025 16:53:35 +0200 Subject: [PATCH 21/33] Use the `scf` prefix in admin commands. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Greg Ziółkowski --- assets/src/js/commands/admin-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/src/js/commands/admin-commands.js b/assets/src/js/commands/admin-commands.js index b2d70291..d15d2cf7 100644 --- a/assets/src/js/commands/admin-commands.js +++ b/assets/src/js/commands/admin-commands.js @@ -164,7 +164,7 @@ wp.domReady( () => { commands.forEach( ( command ) => { commandStore.registerCommand( { - name: 'acf/' + command.name, + name: 'scf/' + command.name, label: command.label, icon: createElement( Icon, { icon: command.icon } ), context: 'admin', From 47c480c93533d8b82416b7f46524e2d8fff46995 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Fri, 25 Apr 2025 16:54:15 +0200 Subject: [PATCH 22/33] Use `scf` prefix for CPT commands --- assets/src/js/commands/custom-post-type-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/src/js/commands/custom-post-type-commands.js b/assets/src/js/commands/custom-post-type-commands.js index ee0962d8..0b8eca6a 100644 --- a/assets/src/js/commands/custom-post-type-commands.js +++ b/assets/src/js/commands/custom-post-type-commands.js @@ -38,7 +38,7 @@ wp.domReady( () => { // Register "View All" command for this post type commandStore.registerCommand( { - name: `acf/cpt-${ postType.name }`, + name: `scf/cpt-${ postType.name }`, label: pluralLabel, icon: createElement( Icon, { icon: 'admin-page' } ), context: 'admin', From 9bed5534a59f86c8c800a4c0fa2a9718cd50510b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor?= <27339341+priethor@users.noreply.github.com> Date: Fri, 25 Apr 2025 17:16:13 +0200 Subject: [PATCH 23/33] Only pass CPTs to the frontend when the array is not empty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Greg Ziółkowski --- includes/admin/admin-commands.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/includes/admin/admin-commands.php b/includes/admin/admin-commands.php index cbfd068d..4df8ce2a 100644 --- a/includes/admin/admin-commands.php +++ b/includes/admin/admin-commands.php @@ -69,13 +69,12 @@ function acf_commands_init() { } } - acf_localize_data( - array( - 'customPostTypes' => $custom_post_types, - ) - ); - if ( ! empty( $custom_post_types ) ) { + acf_localize_data( + array( + 'customPostTypes' => $custom_post_types, + ) + ); wp_enqueue_script( 'commands-custom-post-types' ); } From dfa01042aef3c2ad955ae543216bb176dddebb18 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Fri, 25 Apr 2025 17:22:50 +0200 Subject: [PATCH 24/33] CPT commands: only add label as a keyword if not empty --- assets/src/js/commands/custom-post-type-commands.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/src/js/commands/custom-post-type-commands.js b/assets/src/js/commands/custom-post-type-commands.js index 0b8eca6a..a74b3bf6 100644 --- a/assets/src/js/commands/custom-post-type-commands.js +++ b/assets/src/js/commands/custom-post-type-commands.js @@ -53,7 +53,7 @@ wp.domReady( () => { 'content', 'cpt', postType.name, - postType.label || '', + ...(postType.label ? [postType.label] : []), ], callback: ( { close } ) => { document.location = `${ adminUrl }edit.php?post_type=${ encodeURIComponent( From 54176c5be2d5878ad75144c5dfe6155e40f43b6f Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Fri, 25 Apr 2025 17:26:22 +0200 Subject: [PATCH 25/33] Polish --- assets/src/js/commands/custom-post-type-commands.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/src/js/commands/custom-post-type-commands.js b/assets/src/js/commands/custom-post-type-commands.js index a74b3bf6..810aba60 100644 --- a/assets/src/js/commands/custom-post-type-commands.js +++ b/assets/src/js/commands/custom-post-type-commands.js @@ -53,7 +53,7 @@ wp.domReady( () => { 'content', 'cpt', postType.name, - ...(postType.label ? [postType.label] : []), + ...( postType.label ? [ postType.label ] : [] ), ], callback: ( { close } ) => { document.location = `${ adminUrl }edit.php?post_type=${ encodeURIComponent( @@ -65,7 +65,7 @@ wp.domReady( () => { // Register "Add New" command for this post type commandStore.registerCommand( { - name: `acf/new-${ postType.name }`, + name: `scf/new-${ postType.name }`, label: /* translators: %s: Post type singular label */ sprintf( @@ -86,7 +86,7 @@ wp.domReady( () => { 'create', 'content', postType.name, - postType.label || '', + ...( postType.label ? [ postType.label ] : [] ), ], callback: ( { close } ) => { document.location = `${ adminUrl }post-new.php?post_type=${ encodeURIComponent( From a23722ce0938a3ae68d7182f307fde0b248914a2 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Fri, 25 Apr 2025 18:18:52 +0200 Subject: [PATCH 26/33] Refactor the depencies to user import statements --- assets/src/js/commands/admin-commands.js | 24 +++++++++++------ .../js/commands/custom-post-type-commands.js | 27 ++++++++++++------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/assets/src/js/commands/admin-commands.js b/assets/src/js/commands/admin-commands.js index d15d2cf7..0fd96341 100644 --- a/assets/src/js/commands/admin-commands.js +++ b/assets/src/js/commands/admin-commands.js @@ -8,17 +8,25 @@ * @since 6.5.0 */ -wp.domReady( () => { - if ( ! wp.data?.dispatch?.( 'core/commands' ) || ! acf?.data ) { +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { createElement } from '@wordpress/element'; +import { Icon } from '@wordpress/components'; +import { dispatch } from '@wordpress/data'; +import domReady from '@wordpress/dom-ready'; + +/** + * Register admin commands for SCF + */ +domReady( () => { + if ( ! dispatch( 'core/commands' ) || ! window.acf?.data ) { return; } - const { __ } = wp.i18n; - const { createElement } = wp.element; - const { Icon } = wp.components; - const commandStore = wp.data.dispatch( 'core/commands' ); - - const adminUrl = acf?.data?.admin_url || ''; + const commandStore = dispatch( 'core/commands' ); + const adminUrl = window.acf?.data?.admin_url || ''; const commands = [ { diff --git a/assets/src/js/commands/custom-post-type-commands.js b/assets/src/js/commands/custom-post-type-commands.js index 810aba60..168bbaa4 100644 --- a/assets/src/js/commands/custom-post-type-commands.js +++ b/assets/src/js/commands/custom-post-type-commands.js @@ -11,21 +11,30 @@ * @since 6.5.0 */ -wp.domReady( () => { +/** + * WordPress dependencies + */ +import { __, sprintf } from '@wordpress/i18n'; +import { createElement } from '@wordpress/element'; +import { Icon } from '@wordpress/components'; +import { dispatch } from '@wordpress/data'; +import domReady from '@wordpress/dom-ready'; + +/** + * Register custom post type commands + */ +domReady( () => { // Only proceed when WordPress commands API and there are custom post types accessible if ( - ! wp.data?.dispatch?.( 'core/commands' ) || - ! acf?.data?.customPostTypes?.length + ! dispatch( 'core/commands' ) || + ! window.acf?.data?.customPostTypes?.length ) { return; } - const { __, sprintf } = wp.i18n; - const { createElement } = wp.element; - const { Icon } = wp.components; - const commandStore = wp.data.dispatch( 'core/commands' ); - const adminUrl = acf.data.admin_url || ''; - const postTypes = acf.data.customPostTypes; + const commandStore = dispatch( 'core/commands' ); + const adminUrl = window.acf.data.admin_url || ''; + const postTypes = window.acf.data.customPostTypes; postTypes.forEach( ( postType ) => { // Skip invalid post types From 887f2cfc37816b9e0e91bae04697fef30ce61000 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Fri, 25 Apr 2025 18:47:00 +0200 Subject: [PATCH 27/33] Optimize scripts loading and execution - Defer the script loading (defer was introduced in WP 6.3) - Defer script execution by using the priority queue (introduced in WP 5.0) Since the scripts will only be registered in versions with Command API support, which is 6.3+, we can use both --- assets/src/js/commands/admin-commands.js | 10 ++++++++-- assets/src/js/commands/custom-post-type-commands.js | 10 ++++++++-- includes/assets.php | 10 ++++++++-- package.json | 1 + 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/assets/src/js/commands/admin-commands.js b/assets/src/js/commands/admin-commands.js index 0fd96341..e8c213aa 100644 --- a/assets/src/js/commands/admin-commands.js +++ b/assets/src/js/commands/admin-commands.js @@ -15,12 +15,18 @@ import { __ } from '@wordpress/i18n'; import { createElement } from '@wordpress/element'; import { Icon } from '@wordpress/components'; import { dispatch } from '@wordpress/data'; -import domReady from '@wordpress/dom-ready'; +import { createQueue } from '@wordpress/priority-queue'; + +/** + * Initialize deferred execution queue and context + */ +const queue = createQueue(); +const context = {}; /** * Register admin commands for SCF */ -domReady( () => { +queue.add( context, () => { if ( ! dispatch( 'core/commands' ) || ! window.acf?.data ) { return; } diff --git a/assets/src/js/commands/custom-post-type-commands.js b/assets/src/js/commands/custom-post-type-commands.js index 168bbaa4..142e0832 100644 --- a/assets/src/js/commands/custom-post-type-commands.js +++ b/assets/src/js/commands/custom-post-type-commands.js @@ -18,12 +18,18 @@ import { __, sprintf } from '@wordpress/i18n'; import { createElement } from '@wordpress/element'; import { Icon } from '@wordpress/components'; import { dispatch } from '@wordpress/data'; -import domReady from '@wordpress/dom-ready'; +import { createQueue } from '@wordpress/priority-queue'; + +/** + * Initialize deferred execution queue and context + */ +const queue = createQueue(); +const context = {}; /** * Register custom post type commands */ -domReady( () => { +queue.add( context, () => { // Only proceed when WordPress commands API and there are custom post types accessible if ( ! dispatch( 'core/commands' ) || diff --git a/includes/assets.php b/includes/assets.php index 0167294d..ffb11814 100644 --- a/includes/assets.php +++ b/includes/assets.php @@ -256,7 +256,10 @@ public function register_scripts() { acf_get_url( 'assets/build/js/commands/admin' . $suffix . '.js' ), array( 'acf', 'wp-plugins', 'wp-element', 'wp-components', 'wp-data', 'wp-commands', 'wp-i18n', 'wp-dom-ready' ), $version, - true + array( + 'in_footer' => true, + 'defer' => true, + ) ); wp_register_script( @@ -264,7 +267,10 @@ public function register_scripts() { acf_get_url( 'assets/build/js/commands/custom-post-types' . $suffix . '.js' ), array( 'acf', 'wp-plugins', 'wp-element', 'wp-components', 'wp-data', 'wp-commands', 'wp-i18n', 'wp-dom-ready' ), $version, - true + array( + 'in_footer' => true, + 'defer' => true, + ) ); // Register styles. diff --git a/package.json b/package.json index a976d8a9..82b38299 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@wordpress/dependency-extraction-webpack-plugin": "^6.20.0", "@wordpress/e2e-test-utils-playwright": "^1.20.0", "@wordpress/prettier-config": "^4.22.0", + "@wordpress/priority-queue": "^3.22.0", "@wordpress/scripts": "^30.14.0", "babel-loader": "^9.2.1", "css-loader": "^7.1.2", From 9944ea264a423c0fbaddc8152bca5253680b48b8 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Fri, 25 Apr 2025 18:51:11 +0200 Subject: [PATCH 28/33] Update package-lock.json --- package-lock.json | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/package-lock.json b/package-lock.json index 11f063b6..b1feaf8c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@wordpress/dependency-extraction-webpack-plugin": "^6.20.0", "@wordpress/e2e-test-utils-playwright": "^1.20.0", "@wordpress/prettier-config": "^4.22.0", + "@wordpress/priority-queue": "^3.22.0", "@wordpress/scripts": "^30.14.0", "babel-loader": "^9.2.1", "css-loader": "^7.1.2", @@ -5072,6 +5073,20 @@ "prettier": ">=3" } }, + "node_modules/@wordpress/priority-queue": { + "version": "3.22.0", + "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-3.22.0.tgz", + "integrity": "sha512-mu6I1svNj5dYlbd92Zs/Y0JuEizerOhf/zGlJEbuZPquu+n4MFZR89zYpm+OfXvvr9ixKXSou7J8Ca1UjrZuFw==", + "dev": true, + "dependencies": { + "@babel/runtime": "7.25.7", + "requestidlecallback": "^0.3.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, "node_modules/@wordpress/scripts": { "version": "30.14.0", "resolved": "https://registry.npmjs.org/@wordpress/scripts/-/scripts-30.14.0.tgz", @@ -17669,6 +17684,12 @@ "regjsparser": "bin/parser" } }, + "node_modules/requestidlecallback": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/requestidlecallback/-/requestidlecallback-0.3.0.tgz", + "integrity": "sha512-TWHFkT7S9p7IxLC5A1hYmAYQx2Eb9w1skrXmQ+dS1URyvR8tenMLl4lHbqEOUnpEYxNKpkVMXUgknVpBZWXXfQ==", + "dev": true + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", From 4def3818530f0bb7473c2902771ad6815e3ffa7b Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Fri, 25 Apr 2025 19:04:31 +0200 Subject: [PATCH 29/33] Slight refactor --- assets/src/js/commands/admin-commands.js | 24 +++++++++---------- .../js/commands/custom-post-type-commands.js | 16 ++++++++----- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/assets/src/js/commands/admin-commands.js b/assets/src/js/commands/admin-commands.js index e8c213aa..b900c0d0 100644 --- a/assets/src/js/commands/admin-commands.js +++ b/assets/src/js/commands/admin-commands.js @@ -38,7 +38,7 @@ queue.add( context, () => { { name: 'field-groups', label: __( 'Field Groups', 'secure-custom-fields' ), - url: `${ adminUrl }edit.php?post_type=acf-field-group`, + url: 'edit.php?post_type=acf-field-group', icon: 'layout', description: __( 'SCF: View and manage custom field groups', @@ -54,7 +54,7 @@ queue.add( context, () => { { name: 'new-field-group', label: __( 'Create New Field Group', 'secure-custom-fields' ), - url: `${ adminUrl }post-new.php?post_type=acf-field-group`, + url: 'post-new.php?post_type=acf-field-group', icon: 'plus', description: __( 'SCF: Create a new field group to organize custom fields', @@ -71,7 +71,7 @@ queue.add( context, () => { { name: 'post-types', label: __( 'Post Types', 'secure-custom-fields' ), - url: `${ adminUrl }edit.php?post_type=acf-post-type`, + url: 'edit.php?post_type=acf-post-type', icon: 'admin-post', description: __( 'SCF: Manage custom post types', @@ -82,7 +82,7 @@ queue.add( context, () => { { name: 'new-post-type', label: __( 'Create New Post Type', 'secure-custom-fields' ), - url: `${ adminUrl }post-new.php?post_type=acf-post-type`, + url: 'post-new.php?post_type=acf-post-type', icon: 'plus', description: __( 'SCF: Create a new custom post type', @@ -93,7 +93,7 @@ queue.add( context, () => { { name: 'taxonomies', label: __( 'Taxonomies', 'secure-custom-fields' ), - url: `${ adminUrl }edit.php?post_type=acf-taxonomy`, + url: 'edit.php?post_type=acf-taxonomy', icon: 'category', description: __( 'SCF: Manage custom taxonomies for organizing content', @@ -104,7 +104,7 @@ queue.add( context, () => { { name: 'new-taxonomy', label: __( 'Create New Taxonomy', 'secure-custom-fields' ), - url: `${ adminUrl }post-new.php?post_type=acf-taxonomy`, + url: 'post-new.php?post_type=acf-taxonomy', icon: 'plus', description: __( 'SCF: Create a new custom taxonomy', @@ -122,7 +122,7 @@ queue.add( context, () => { { name: 'options-pages', label: __( 'Options Pages', 'secure-custom-fields' ), - url: `${ adminUrl }edit.php?post_type=acf-ui-options-page`, + url: 'edit.php?post_type=acf-ui-options-page', icon: 'admin-settings', description: __( 'SCF: Manage custom options pages for global settings', @@ -133,7 +133,7 @@ queue.add( context, () => { { name: 'new-options-page', label: __( 'Create New Options Page', 'secure-custom-fields' ), - url: `${ adminUrl }post-new.php?post_type=acf-ui-options-page`, + url: 'post-new.php?post_type=acf-ui-options-page', icon: 'plus', description: __( 'SCF: Create a new custom options page', @@ -144,7 +144,7 @@ queue.add( context, () => { { name: 'tools', label: __( 'SCF Tools', 'secure-custom-fields' ), - url: `${ adminUrl }admin.php?page=acf-tools`, + url: 'admin.php?page=acf-tools', icon: 'admin-tools', description: __( 'SCF: Access SCF utility tools', @@ -155,7 +155,7 @@ queue.add( context, () => { { name: 'import', label: __( 'Import SCF Data', 'secure-custom-fields' ), - url: `${ adminUrl }admin.php?page=acf-tools&tool=import`, + url: 'admin.php?page=acf-tools&tool=import', icon: 'upload', description: __( 'SCF: Import field groups, post types, taxonomies, and options pages', @@ -166,7 +166,7 @@ queue.add( context, () => { { name: 'export', label: __( 'Export SCF Data', 'secure-custom-fields' ), - url: `${ adminUrl }admin.php?page=acf-tools&tool=export`, + url: 'admin.php?page=acf-tools&tool=export', icon: 'download', description: __( 'SCF: Export field groups, post types, taxonomies, and options pages', @@ -185,7 +185,7 @@ queue.add( context, () => { description: command.description, keywords: command.keywords, callback: ( { close } ) => { - document.location = command.url; + document.location = adminUrl + command.url; close(); }, } ); diff --git a/assets/src/js/commands/custom-post-type-commands.js b/assets/src/js/commands/custom-post-type-commands.js index 142e0832..38676e64 100644 --- a/assets/src/js/commands/custom-post-type-commands.js +++ b/assets/src/js/commands/custom-post-type-commands.js @@ -71,9 +71,11 @@ queue.add( context, () => { ...( postType.label ? [ postType.label ] : [] ), ], callback: ( { close } ) => { - document.location = `${ adminUrl }edit.php?post_type=${ encodeURIComponent( - postType.name - ) }`; + document.location = + adminUrl + + `edit.php?post_type=${ encodeURIComponent( + postType.name + ) }`; close(); }, } ); @@ -104,9 +106,11 @@ queue.add( context, () => { ...( postType.label ? [ postType.label ] : [] ), ], callback: ( { close } ) => { - document.location = `${ adminUrl }post-new.php?post_type=${ encodeURIComponent( - postType.name - ) }`; + document.location = + adminUrl + + `post-new.php?post_type=${ encodeURIComponent( + postType.name + ) }`; close(); }, } ); From 1df01fef85a3c381c9ece2d8a291264730230184 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Fri, 25 Apr 2025 19:10:51 +0200 Subject: [PATCH 30/33] Assets: remove redundant registrations, prefix registered scritps --- includes/admin/admin-commands.php | 4 ++-- includes/assets.php | 16 ++++------------ webpack.config.js | 4 ++-- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/includes/admin/admin-commands.php b/includes/admin/admin-commands.php index 4df8ce2a..115a0a8f 100644 --- a/includes/admin/admin-commands.php +++ b/includes/admin/admin-commands.php @@ -75,12 +75,12 @@ function acf_commands_init() { 'customPostTypes' => $custom_post_types, ) ); - wp_enqueue_script( 'commands-custom-post-types' ); + wp_enqueue_script( 'scf-commands-custom-post-types' ); } // Only load admin commands if user has SCF admin capabilities. if ( current_user_can( acf_get_setting( 'capability' ) ) ) { - wp_enqueue_script( 'commands-admin' ); + wp_enqueue_script( 'scf-commands-admin' ); } } diff --git a/includes/assets.php b/includes/assets.php index ffb11814..5b166adb 100644 --- a/includes/assets.php +++ b/includes/assets.php @@ -243,17 +243,9 @@ public function register_scripts() { ); } - // Register core scripts - wp_register_script( 'acf', acf_get_url( 'assets/build/js/acf' . $suffix . '.js' ), array( 'jquery' ), $version, false ); - wp_register_script( 'acf-input', acf_get_url( 'assets/build/js/acf-input' . $suffix . '.js' ), array( 'jquery', 'jquery-ui-sortable', 'jquery-ui-resizable', 'acf', 'wp-a11y' ), $version, false ); - wp_register_script( 'acf-field-group', acf_get_url( 'assets/build/js/acf-field-group' . $suffix . '.js' ), array( 'acf-input' ), $version, false ); - wp_register_script( 'acf-internal-post-type', acf_get_url( 'assets/build/js/acf-internal-post-type' . $suffix . '.js' ), array( 'acf-input' ), $version, false ); - wp_register_script( 'acf-escaped-html-notice', acf_get_url( 'assets/build/js/acf-escaped-html-notice' . $suffix . '.js' ), array( 'jquery' ), $version, true ); - - // Register WordPress commands integration wp_register_script( - 'commands-admin', - acf_get_url( 'assets/build/js/commands/admin' . $suffix . '.js' ), + 'scf-commands-admin', + acf_get_url( 'assets/build/js/commands/scf-admin' . $suffix . '.js' ), array( 'acf', 'wp-plugins', 'wp-element', 'wp-components', 'wp-data', 'wp-commands', 'wp-i18n', 'wp-dom-ready' ), $version, array( @@ -263,8 +255,8 @@ public function register_scripts() { ); wp_register_script( - 'commands-custom-post-types', - acf_get_url( 'assets/build/js/commands/custom-post-types' . $suffix . '.js' ), + 'scf-commands-custom-post-types', + acf_get_url( 'assets/build/js/commands/scf-custom-post-types' . $suffix . '.js' ), array( 'acf', 'wp-plugins', 'wp-element', 'wp-components', 'wp-data', 'wp-commands', 'wp-i18n', 'wp-dom-ready' ), $version, array( diff --git a/webpack.config.js b/webpack.config.js index 4ae1cb0f..699b7fe2 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -15,8 +15,8 @@ const commonConfig = { 'js/acf-input': './assets/src/js/acf-input.js', 'js/acf-internal-post-type': './assets/src/js/acf-internal-post-type.js', - 'js/commands/admin': './assets/src/js/commands/admin-commands.js', - 'js/commands/custom-post-types': './assets/src/js/commands/custom-post-type-commands.js', + 'js/commands/scf-admin': './assets/src/js/commands/admin-commands.js', + 'js/commands/scf-custom-post-types': './assets/src/js/commands/custom-post-type-commands.js', 'js/acf': './assets/src/js/acf.js', 'js/pro/acf-pro-blocks': './assets/src/js/pro/acf-pro-blocks.js', 'js/pro/acf-pro-field-group': From ccb0edc0cb38f5dea29a7bbbe64eb545f66d4cb8 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Mon, 28 Apr 2025 11:41:16 +0200 Subject: [PATCH 31/33] Remove redundant admin check --- includes/admin/admin-commands.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/includes/admin/admin-commands.php b/includes/admin/admin-commands.php index 115a0a8f..31549f7c 100644 --- a/includes/admin/admin-commands.php +++ b/includes/admin/admin-commands.php @@ -26,11 +26,6 @@ * @since 6.5.0 */ function acf_commands_init() { - // Only load on admin screens. - if ( ! is_admin() ) { - return; - } - // Ensure we only load our commands where the WordPress commands API is available. if ( ! wp_script_is( 'wp-commands', 'registered' ) ) { return; From b5f91998944a2d09cb2ebfc6d4414a4052e26c14 Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Mon, 28 Apr 2025 12:01:06 +0200 Subject: [PATCH 32/33] Remove unnecesary checking of `acf_get_acf_post_types` --- includes/admin/admin-commands.php | 46 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/includes/admin/admin-commands.php b/includes/admin/admin-commands.php index 31549f7c..5d84425c 100644 --- a/includes/admin/admin-commands.php +++ b/includes/admin/admin-commands.php @@ -33,34 +33,32 @@ function acf_commands_init() { $custom_post_types = array(); - if ( function_exists( 'acf_get_acf_post_types' ) ) { - $scf_post_types = acf_get_acf_post_types(); + $scf_post_types = acf_get_acf_post_types(); - foreach ( $scf_post_types as $post_type ) { - // Skip if post type name is not set (defensive) or post type is inactive. - if ( empty( $post_type['post_type'] ) || ( isset( $post_type['active'] ) && ! $post_type['active'] ) ) { - continue; - } + foreach ( $scf_post_types as $post_type ) { + // Skip if post type name is not set (defensive) or post type is inactive. + if ( empty( $post_type['post_type'] ) || ( isset( $post_type['active'] ) && ! $post_type['active'] ) ) { + continue; + } - $plural_label = $post_type['labels']['name'] ?? $post_type['label'] ?? $post_type['post_type']; - $singular_label = $post_type['labels']['singular_name'] ?? $post_type['singular_label'] ?? $plural_label; + $plural_label = $post_type['labels']['name'] ?? $post_type['label'] ?? $post_type['post_type']; + $singular_label = $post_type['labels']['singular_name'] ?? $post_type['singular_label'] ?? $plural_label; - $post_type_obj = get_post_type_object( $post_type['post_type'] ); + $post_type_obj = get_post_type_object( $post_type['post_type'] ); - // Three conditions must be met to include this post type in the commands: - // 1. Post type object must exist - // 2. Current user must have permission to edit posts of this type. - // 3. Post type must have admin UI enabled (show_ui setting). - if ( $post_type_obj && - current_user_can( $post_type_obj->cap->edit_posts ) && - $post_type_obj->show_ui ) { - $custom_post_types[] = array( - 'name' => $post_type['post_type'], - 'label' => $plural_label, - 'singular_label' => $singular_label, - 'icon' => $post_type['menu_icon'] ?? '', - ); - } + // Three conditions must be met to include this post type in the commands: + // 1. Post type object must exist + // 2. Current user must have permission to edit posts of this type. + // 3. Post type must have admin UI enabled (show_ui setting). + if ( $post_type_obj && + current_user_can( $post_type_obj->cap->edit_posts ) && + $post_type_obj->show_ui ) { + $custom_post_types[] = array( + 'name' => $post_type['post_type'], + 'label' => $plural_label, + 'singular_label' => $singular_label, + 'icon' => $post_type['menu_icon'] ?? '', + ); } } From 71342ac399ed7169e8069cab83b248ea99a9335c Mon Sep 17 00:00:00 2001 From: priethor <27339341+priethor@users.noreply.github.com> Date: Mon, 28 Apr 2025 12:11:10 +0200 Subject: [PATCH 33/33] Change the priority queue to a simpler `requestIdleCallback` --- assets/src/js/commands/admin-commands.js | 17 ++++++++--------- .../js/commands/custom-post-type-commands.js | 17 ++++++++--------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/assets/src/js/commands/admin-commands.js b/assets/src/js/commands/admin-commands.js index b900c0d0..4756a1ec 100644 --- a/assets/src/js/commands/admin-commands.js +++ b/assets/src/js/commands/admin-commands.js @@ -15,18 +15,11 @@ import { __ } from '@wordpress/i18n'; import { createElement } from '@wordpress/element'; import { Icon } from '@wordpress/components'; import { dispatch } from '@wordpress/data'; -import { createQueue } from '@wordpress/priority-queue'; - -/** - * Initialize deferred execution queue and context - */ -const queue = createQueue(); -const context = {}; /** * Register admin commands for SCF */ -queue.add( context, () => { +const registerAdminCommands = () => { if ( ! dispatch( 'core/commands' ) || ! window.acf?.data ) { return; } @@ -190,4 +183,10 @@ queue.add( context, () => { }, } ); } ); -} ); +}; + +if ( 'requestIdleCallback' in window ) { + window.requestIdleCallback( registerAdminCommands, { timeout: 500 } ); +} else { + setTimeout( registerAdminCommands, 500 ); +} diff --git a/assets/src/js/commands/custom-post-type-commands.js b/assets/src/js/commands/custom-post-type-commands.js index 38676e64..9b7ce140 100644 --- a/assets/src/js/commands/custom-post-type-commands.js +++ b/assets/src/js/commands/custom-post-type-commands.js @@ -18,18 +18,11 @@ import { __, sprintf } from '@wordpress/i18n'; import { createElement } from '@wordpress/element'; import { Icon } from '@wordpress/components'; import { dispatch } from '@wordpress/data'; -import { createQueue } from '@wordpress/priority-queue'; - -/** - * Initialize deferred execution queue and context - */ -const queue = createQueue(); -const context = {}; /** * Register custom post type commands */ -queue.add( context, () => { +const registerPostTypeCommands = () => { // Only proceed when WordPress commands API and there are custom post types accessible if ( ! dispatch( 'core/commands' ) || @@ -115,4 +108,10 @@ queue.add( context, () => { }, } ); } ); -} ); +}; + +if ( 'requestIdleCallback' in window ) { + window.requestIdleCallback( registerPostTypeCommands, { timeout: 500 } ); +} else { + setTimeout( registerPostTypeCommands, 500 ); +}