array('build', __('Field groups', 'customfields-com'), __('Create and edit the fields for your content.', 'customfields-com')), 'customfields-welcome' => array('support', __('Welcome choices', 'customfields-com'), __('Choose optional site registration and email preferences.', 'customfields-com')), 'customfields-start' => array('build', __('Use your fields', 'customfields-com'), __('Preview real saved content and continue your work.', 'customfields-com')), 'customfields-csv-check' => array('move', __('Compare a CSV', 'customfields-com'), __('See every supported row outcome and keep manual fixes available.', 'customfields-com')), 'customfields-health' => array('check', __('Content checks', 'customfields-com'), __('Check content and compare definitions with clear coverage.', 'customfields-com')), 'customfields-maintenance' => array('check', __('Maintenance', 'customfields-com'), __('Save checks, review changes and retain local maintenance history.', 'customfields-com')), 'customfields-content-types' => array('build', __('Content types', 'customfields-com'), __('Register the content types and taxonomies your site needs.', 'customfields-com')), 'customfields-pro-options' => array('build', __('Site options', 'customfields-com'), __('Edit the details that your whole site shares.', 'customfields-com')), 'customfields-publishing' => array('publish', __('Blocks & listings', 'customfields-com'), __('Free blocks and basic display. Pro creates and configures directories and listings. Existing saved listings keep rendering.', 'customfields-com')), 'customfields-pro-import' => array('move', __('Import field definitions', 'customfields-com'), __('Bring across an ACF field structure before moving its values.', 'customfields-com')), 'customfields-workflows' => array('move', __('History & migrations', 'customfields-com'), __('Review the source, check the destination, then copy with recovery.', 'customfields-com')), 'customfields-sync' => array('move', __('Definition files', 'customfields-com'), __('Import a local definition file or download the current setup.', 'customfields-com')), 'customfields-storage' => array('move', __('Value storage', 'customfields-com'), __('Manage optional table storage without losing the native copy.', 'customfields-com')), 'customfields-csv' => array('move', __('CSV workflows', 'customfields-com'), __('Reuse column mappings, review changes and update existing content.', 'customfields-com')), 'customfields-submissions' => array('publish', __('Submission forms', 'customfields-com'), __('Review new entries and proposed changes with assigned reviewers.', 'customfields-com')), 'customfields-agency' => array('move', __('Move field setup', 'customfields-com'), __('Package field and content definitions, then review them on another site.', 'customfields-com')), 'customfields-transfer' => array('move', __('Content & media', 'customfields-com'), __('Copy selected content and its local media with review and recovery.', 'customfields-com')), 'customfields-bulk' => array('build', __('Bulk editor', 'customfields-com'), __('Make a careful change across your content, with review and undo.', 'customfields-com')), 'customfields-pro-license' => array('support', __('Licence & updates', 'customfields-com'), __('Activate Pro on this site and manage optional update services.', 'customfields-com')), 'customfields-pro-preview' => array('support', __('Explore Pro', 'customfields-com'), __('Try local examples of reviewed business workflows.', 'customfields-com')), ); } /** Fixed preview destinations; these links never register or authorize a Pro operation. */ private static function pro_tools() { return array( 'customfields-bulk' => 'bulk', 'customfields-submissions' => 'submissions', 'customfields-csv' => 'csv', 'customfields-agency' => 'deploy', 'customfields-transfer' => 'transfer', 'customfields-maintenance' => 'maintenance', ); } private static function active() { return isset(self::routes()[self::page()]) && (current_user_can('manage_options') || (self::page() === 'customfields-submissions' && current_user_can('customfields_review_submissions'))); } public static function body($classes) { return self::active() ? $classes . ' cf-unified cf-route-' . self::page() : $classes; } public static function assets() { if (!self::active()) { return; } wp_enqueue_style('customfields-workspace', CUSTOMFIELDS_URL . 'assets/workspace.css', array('customfields-admin'), CUSTOMFIELDS_VERSION); wp_enqueue_script('customfields-workspace', CUSTOMFIELDS_URL . 'assets/workspace.js', array('wp-i18n'), CUSTOMFIELDS_VERSION, true); wp_set_script_translations('customfields-workspace', 'customfields-com', CUSTOMFIELDS_PATH . 'languages'); if (in_array(self::page(), array('customfields-workflows', 'customfields-agency', 'customfields-transfer', 'customfields-sync'), true)) { wp_enqueue_style('customfields-flows', CUSTOMFIELDS_URL . 'assets/flows.css', array('customfields-workspace'), CUSTOMFIELDS_VERSION); wp_enqueue_script('customfields-flows', CUSTOMFIELDS_URL . 'assets/flows.js', array('customfields-workspace', 'wp-i18n'), CUSTOMFIELDS_VERSION, true); wp_set_script_translations('customfields-flows', 'customfields-com', CUSTOMFIELDS_PATH . 'languages'); wp_localize_script('customfields-flows', 'CustomFieldsFlows', array( 'fields' => __('Choose your fields', 'customfields-com'), 'content' => __('Choose your content', 'customfields-com'), 'review' => __('Review changes', 'customfields-com'), 'next' => __('Next: choose content', 'customfields-com'), 'back' => __('Back to fields', 'customfields-com'), 'search' => __('Find an item in this review', 'customfields-com'), 'previous' => __('Previous items', 'customfields-com'), 'more' => __('Next items', 'customfields-com'), 'scope' => /* translators: %d: Number of reviewed items. */ __('All %d reviewed items remain in this operation. Filtering only changes this view.', 'customfields-com'), 'page' => /* translators: 1: First visible match; 2: last visible match; 3: total matches. */ __('Showing %1$d–%2$d of %3$d matches', 'customfields-com'), 'empty' => __('No matching items. Clear the search to see the full review.', 'customfields-com'), 'all' => __('Select all in this section', 'customfields-com'), 'clear' => __('Clear this section', 'customfields-com'), 'selected' => /* translators: %d: Number of selected items. */ __('%d selected', 'customfields-com'), )); } wp_localize_script('customfields-workspace', 'CustomFieldsWorkspace', array( 'page' => self::page(), 'preferenceKey' => 'customfields-studio-' . substr(hash('sha256', home_url('/')), 0, 16) . '-' . get_current_blog_id() . '-' . get_current_user_id(), 'description' => self::routes()[self::page()][2], 'labels' => array( 'details' => __('Details & limits', 'customfields-com'), 'noTools' => __('No matching tools. Try “fields”, “move” or “publish”.', 'customfields-com'), 'identity' => __('Name and identify', 'customfields-com'), 'content' => __('Choose the content', 'customfields-com'), 'appearance' => __('Choose the display', 'customfields-com'), 'controls' => __('Add the editing controls', 'customfields-com'), 'filter' => __('Narrow and sort the results', 'customfields-com'), 'save' => __('Save and use it', 'customfields-com'), 'technical' => __('Advanced identifiers', 'customfields-com'), 'draft' => __('Unsaved changes', 'customfields-com'), 'draftNotice' => __('You have changes on this page. Leave without saving?', 'customfields-com'), 'guidance' => __('Guidance & recent checks', 'customfields-com'), 'showWordPress' => __('Show WordPress', 'customfields-com'), 'focusWorkspace' => __('Focus workspace', 'customfields-com'), 'copied' => __('Copied', 'customfields-com'), 'copy' => __('Copy', 'customfields-com'), ), )); } public static function shell() { if (!self::active()) { return; } global $submenu; $allowed = array(); foreach ($submenu['customfields'] ?? array() as $item) { if (isset($item[2], $item[1]) && current_user_can($item[1])) { $allowed[$item[2]] = true; } } if (self::page() === 'customfields-submissions' && current_user_can('customfields_review_submissions')) { $allowed['customfields-submissions'] = true; } $routes = array_intersect_key(self::routes(), $allowed); $page = self::page(); if (!isset($routes[$page])) { return; } $tools = self::pro_tools(); $previews = array(); $urls = array(); $current = $page; // Free administrators can explore local previews. Active Pro keeps its registered capability-filtered routes. if (!self::pro_available() && current_user_can('manage_options') && isset($routes['customfields-pro-preview'])) { $previews = ProDiscovery::preview_tabs_hidden() ? array() : $tools; $routes = array_diff_key($routes, $tools); $routes = array_intersect_key(self::routes(), $routes + $previews); } // A directly opened installed-tool page keeps a valid breadcrumb even with preview links hidden. if (!isset($routes[$page])) { $routes[$page] = self::routes()[$page]; } $feature = isset($_GET['feature']) && is_string($_GET['feature']) ? wp_unslash($_GET['feature']) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Read-only selection must exactly match the fixed preview map below; it is never reflected or used to authorize a mutation. foreach ($routes as $key => $route) { $urls[$key] = isset($previews[$key]) ? add_query_arg(array('page' => 'customfields-pro-preview', 'feature' => $previews[$key]), admin_url('admin.php')) : admin_url('admin.php?page=' . $key); if ($page === 'customfields-pro-preview' && isset($previews[$key]) && $feature === $previews[$key]) { $current = $key; } } // Fixed documentation links are available in navigation and the finder; opening them shares no saved field values. $help = array('customfields-docs' => 'https://customfields.com/docs/', 'customfields-support' => 'https://customfields.com/help/'); $routes['customfields-docs'] = array('support', __('Getting started', 'customfields-com'), __('Documentation: create fields, enter values and display your content.', 'customfields-com')); $routes['customfields-support'] = array('support', __('Get support', 'customfields-com'), __('Ask for help or report a problem with CustomFields.', 'customfields-com')); $urls = array_merge($urls, $help); $categories = array('build' => __('Build & edit', 'customfields-com'), 'publish' => __('Publish', 'customfields-com'), 'move' => __('Move data', 'customfields-com'), 'check' => __('Check content', 'customfields-com'), 'support' => __('Help & updates', 'customfields-com')); $pro = self::pro_available(); $icons = array('build' => 'screenoptions', 'publish' => 'layout', 'move' => 'randomize', 'check' => 'yes-alt', 'support' => 'sos'); echo '

' . esc_html__('What would you like to do?', 'customfields-com') . '

'; } }