[], 'meta' => [], 'acf' => [], 'terms' => []]; foreach ($catalog['post_types'] ?? [] as $type) { foreach ($type['taxonomies'] ?? [] as $taxonomy) { $key = $taxonomy['slug'] ?? ''; if (!$key) continue; $options['taxonomy'][$key] = ['label' => display_label($taxonomy['label'] ?? $key), 'public' => $taxonomy['public'] ?? true]; foreach ($taxonomy['terms'] ?? [] as $term) { $slug = $term['slug'] ?? ''; if ($slug !== '') $options['terms'][$key][$slug] = ['label' => display_label($term['name'] ?? $slug)]; } } foreach (['meta' => 'meta_fields', 'acf' => 'acf_fields'] as $kind => $field_key) { foreach ($type[$field_key] ?? [] as $field) { $key = $kind === 'meta' ? ($field['key'] ?? '') : ($field['name'] ?? ''); if ($key !== '') $options[$kind][$key] = ['label' => display_label($field['label'] ?? $key)]; } } } foreach (['taxonomy', 'meta', 'acf'] as $kind) uasort($options[$kind], static fn($a, $b) => strnatcasecmp($a['label'], $b['label'])); ksort($options['terms'], SORT_NATURAL | SORT_FLAG_CASE); foreach ($options['terms'] as &$terms) uasort($terms, static fn($a, $b) => strnatcasecmp($a['label'], $b['label'])); unset($terms); return $options; } function render_option($name, $value, $key, $option, $excluded) { ?> __('Global exclusions saved. They apply immediately; no catalog rebuild is needed.', 'accomplice-query-loop-filters'), 'defaults' => __('Default global exclusions restored. No catalog rebuild is needed.', 'accomplice-query-loop-filters'), ]; if (isset($messages[$notice])) printf('

%s

', esc_html($messages[$notice])); ?>

__('Taxonomy sources', 'accomplice-query-loop-filters'), 'meta' => __('Metadata fields', 'accomplice-query-loop-filters'), 'acf' => __('ACF fields', 'accomplice-query-loop-filters')] as $kind => $label) : ?>
()
$option) render_option('exclusions[' . $kind . '][]', $key, $key, $option, in_array((string) $key, $settings[$kind], true)); ?>

$terms) : ?>
> ()
$option) { $term = ['taxonomy' => (string) $taxonomy, 'slug' => (string) $slug]; render_option('exclusions[terms][]', wp_json_encode($term), $slug, $option, in_array($term, $settings['terms'], true)); } ?>

[], 'meta' => [], 'acf' => [], 'terms' => []]; foreach (['taxonomy', 'meta', 'acf'] as $kind) $settings[$kind] = isset($posted[$kind]) && is_array($posted[$kind]) ? $posted[$kind] : []; foreach (isset($posted['terms']) && is_array($posted['terms']) ? $posted['terms'] : [] as $encoded) { $term = is_string($encoded) ? json_decode($encoded, true) : null; if (is_array($term)) $settings['terms'][] = $term; } return Exclusions\sanitize_settings($settings); } function handle_save() { if (!current_user_can('manage_options')) wp_die(esc_html__('You cannot change these settings.', 'accomplice-query-loop-filters')); check_admin_referer('fqbpro_catalog_save_exclusions'); $operation = isset($_POST['operation']) && is_string($_POST['operation']) ? sanitize_key(wp_unslash($_POST['operation'])) : ''; if ($operation === 'defaults') { Exclusions\save_settings(Exclusions\defaults()); } elseif ($operation === 'save') { $complete = isset($_POST['fqbpro_exclusions_complete']) && is_string($_POST['fqbpro_exclusions_complete']) ? sanitize_text_field(wp_unslash($_POST['fqbpro_exclusions_complete'])) : ''; if ($complete !== '1') wp_die(esc_html__('The exclusion form was incomplete. Return to Catalog Data and save a smaller selection, or ask your administrator to increase the PHP input limit. No exclusions were changed.', 'accomplice-query-loop-filters')); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitize_posted_settings decodes term JSON and validates every field through the shared structured normalizer, preserving exact metadata keys and encoded term slugs. $settings = sanitize_posted_settings(isset($_POST['exclusions']) && is_array($_POST['exclusions']) ? wp_unslash($_POST['exclusions']) : []); Exclusions\save_settings($settings); } else { wp_die(esc_html__('Unknown exclusions action.', 'accomplice-query-loop-filters')); } wp_safe_redirect(add_query_arg(['page' => 'fqbpro-catalog', 'tab' => 'catalog', 'fqbpro_exclusions_notice' => $operation === 'defaults' ? 'defaults' : 'saved'], admin_url('admin.php'))); exit; }