diff --git a/assets/script.js b/assets/script.js index 2f81fda..bffc3e0 100644 --- a/assets/script.js +++ b/assets/script.js @@ -8,91 +8,41 @@ jQuery(document).ready(function ($) { */ function triggerFiltering(paged = 1) { let searchTerm = $('#search').val(); + let appliedFilters = []; - let appliedFilters = []; - let typeFilters = []; - let subjectFilters = []; + // Collect selected taxonomy filters dynamically + let taxonomyFilters = {}; + $('input[type="checkbox"]:checked').each(function () { + let taxonomy = $(this).attr('name').replace('[]', ''); // Extract taxonomy name - let selectedTypes = $('input[name="resource_type[]"]:checked') - .map(function () { - return $(this).closest('label').text().trim(); - }) - .get(); + if (!taxonomyFilters[taxonomy]) { + taxonomyFilters[taxonomy] = []; + } - let selectedSubjects = $('input[name="resource_subject[]"]:checked') - .map(function () { - return $(this).closest('label').text().trim(); - }) - .get(); + taxonomyFilters[taxonomy].push($(this).val()); + }); - // Search Term - if (searchTerm) { - appliedFilters.push( - ` - Search: "${searchTerm}" - - ` - ); + // Build applied filters for display + for (let taxonomy in taxonomyFilters) { + taxonomyFilters[taxonomy].forEach(function (term) { + appliedFilters.push( + ` + ${taxonomy}: ${term} + + ` + ); + }); } - // Resource Types - $('input[name="resource_type[]"]:checked').each(function () { - const slug = $(this).val(); // Get the slug - const name = $(this).closest('label').text().trim(); // Get the name - - appliedFilters.push( - ` - Type: ${name} - - ` - ); - - typeFilters.push( - `${name}` - ); - }); - - // Resource Subjects - selectedSubjects.forEach(function (subject) { - appliedFilters.push( - ` - Subject: ${subject} - - ` - ); - - subjectFilters.push( - `${subject}` - ); - }); - - $('#applied-filters').html( - appliedFilters.length ? appliedFilters.join(' ') : 'None' - ); - - $('#type_text').html( - typeFilters.length ? typeFilters.join(', ') : 'Resource Type' - ); - $('#subject_text').html( - subjectFilters.length ? subjectFilters.join(', ') : 'Subject Tags' - ); + $('#applied-filters').html(appliedFilters.length ? appliedFilters.join(' ') : 'None'); let formData = { action: 'filter_resources', nonce: resourceFilterAjax.nonce, search: searchTerm, paged: paged, - sort_order: $('#sort-order').val(), - resource_type: $('input[name="resource_type[]"]:checked') - .map(function () { - return this.value; - }) - .get(), - resource_subject: $('input[name="resource_subject[]"]:checked') - .map(function () { - return this.value; - }) - .get(), + sort_order: $('#sortOrder').val(), + ...taxonomyFilters, // Include taxonomy filters dynamically }; // Perform AJAX request @@ -112,7 +62,7 @@ jQuery(document).ready(function ($) { } // Handle sort order change - $('#sort-order').on('change', function () { + $('#sortOrder').on('change', function () { triggerFiltering(); }); @@ -148,18 +98,13 @@ jQuery(document).ready(function ($) { // Remove the corresponding filter if (filterType === 'search') { $('#search').val(''); - } else if (filterType === 'resource_type') { - $('input[name="resource_type[]"]:checked').each(function () { + } else { + // Dynamically handle taxonomy filters + $(`input[name="${filterType}[]"]:checked`).each(function () { if ($(this).val() === filterValue) { // Match the slug, not the name $(this).prop('checked', false); } }); - } else if (filterType === 'resource_subject') { - $('input[name="resource_subject[]"]:checked').each(function () { - if ($(this).closest('label').text().trim() === filterValue) { - $(this).prop('checked', false); - } - }); } // Re-trigger filtering after removing the filter diff --git a/resource-filter.php b/resource-filter.php index 5f1a03c..dd61ed4 100644 --- a/resource-filter.php +++ b/resource-filter.php @@ -67,13 +67,13 @@ class ContentFilterPlugin { if ($_SERVER['REQUEST_METHOD'] === 'POST') { check_admin_referer('content_filter_settings'); - $post_types = isset($_POST['post_types']) ? array_map('sanitize_text_field', $_POST['post_types']) : []; + $postTypes = isset($_POST['post_types']) ? array_map('sanitize_text_field', $_POST['post_types']) : []; $taxonomies = isset($_POST['taxonomies']) ? array_map('sanitize_text_field', $_POST['taxonomies']) : []; $posts_per_page = isset($_POST['posts_per_page']) ? intval($_POST['posts_per_page']) : 12; $homepage_taxonomy = isset($_POST['homepage_taxonomy']) ? sanitize_text_field($_POST['homepage_taxonomy']) : ''; update_option('content_filter_homepage_taxonomy', $homepage_taxonomy); - update_option('content_filter_post_types', $post_types); + update_option('content_filter_post_types', $postTypes); update_option('content_filter_taxonomies', $taxonomies); update_option('content_filter_posts_per_page', $posts_per_page); @@ -81,7 +81,7 @@ class ContentFilterPlugin { } // Get saved options - $post_types = get_option('content_filter_post_types', []); + $postTypes = get_option('content_filter_post_types', []); $taxonomies = get_option('content_filter_taxonomies', []); $posts_per_page = get_option('content_filter_posts_per_page', 12); $homepage_taxonomy = get_option('content_filter_homepage_taxonomy', ''); @@ -99,7 +99,7 @@ class ContentFilterPlugin {

Select the post types to include in the filter.


@@ -129,7 +129,7 @@ class ContentFilterPlugin { -

+

get_option('content_filter_post_types', ['post']), - 'posts_per_page' => get_option('content_filter_posts_per_page', 12), + 'post_type' => $postTypes, + 'posts_per_page' => $postCount, 'paged' => max(1, get_query_var('paged', 1)), // Get current page number 'tax_query' => $this->buildDynamicTaxQuery(), - 's' => isset($_POST['search']) ? sanitize_text_field($_POST['search']) : '', + 's' => $strSearch, ]; // Sorting logic $query_args = $this->applySorting($query_args, $sort_order); - $tax_query = []; - - if (!empty($_POST['resource_type'])) { - $resType = is_array($_POST['resource_type']) ? array_map('sanitize_text_field', $_POST['resource_type']) : sanitize_text_field($_POST['resource_type']); - - $query_args['tax_query'][] = [ - 'taxonomy' => 'resource_type', - 'field' => 'slug', - 'terms' => $resType, - 'operator' => 'IN' - ]; - } - - if (!empty($_POST['resource_subject'])) { - $query_args['tax_query'][] = [ - 'taxonomy' => 'resource_subject', - 'field' => 'slug', - 'terms' => array_map('sanitize_text_field', $_POST['resource_subject']), - 'operator' => 'IN' - ]; - } - - if (!empty($tax_query)) { - $query_args['tax_query'] = [ - 'relation' => 'AND', // Both filters must match - ...$tax_query - ]; - } - return new WP_Query($query_args); } else { return new WP_Query([ - 'post_type' => get_option('content_filter_post_types', ['post']), - 'posts_per_page' => get_option('content_filter_posts_per_page', 12), + 'post_type' => $postTypes, + 'posts_per_page' => $postCount, 'paged' => max(1, get_query_var('paged', 1)), // Get current page number + 'tax_query' => $this->buildDynamicTaxQuery(), + 's' => $strSearch, ]); } } @@ -365,27 +343,27 @@ class ContentFilterPlugin { switch ($sort_order) { case 'date_asc': $query_args['orderby'] = 'date'; - $query_args['order'] = 'ASC'; + $query_args['order'] = 'ASC'; break; case 'date_desc': $query_args['orderby'] = 'date'; - $query_args['order'] = 'DESC'; + $query_args['order'] = 'DESC'; break; case 'title_asc': $query_args['orderby'] = 'title'; - $query_args['order'] = 'ASC'; + $query_args['order'] = 'ASC'; break; case 'title_desc': $query_args['orderby'] = 'title'; - $query_args['order'] = 'DESC'; + $query_args['order'] = 'DESC'; break; default: $query_args['orderby'] = 'date'; - $query_args['order'] = 'DESC'; + $query_args['order'] = 'DESC'; } return $query_args; @@ -469,20 +447,21 @@ class ContentFilterPlugin { * @since 1.0.0 */ private function buildQueryArgs() { - $post_types = get_option('content_filter_post_types', []); - + $postTypes = get_option('content_filter_post_types', []); + $postCount = get_option('content_filter_posts_per_page', 12); // Get posts per page from admin + $strSearch = isset($_POST['search']) ? sanitize_text_field($_POST['search']) : ''; $sort_order = isset($_POST['sort_order']) ? sanitize_text_field($_POST['sort_order']) : 'date_desc'; $query_args = [ - 'post_type' => !empty($post_types) ? $post_types : ['post'], - 'posts_per_page' => get_option('content_filter_posts_per_page', 12), + 'post_type' => !empty($postTypes) ? $postTypes : ['post'], + 'posts_per_page' => $postCount, 'paged' => isset($_POST['paged']) ? intval($_POST['paged']) : 1, // Get current page number 'tax_query' => $this->buildDynamicTaxQuery(), - 's' => isset($_POST['search']) ? sanitize_text_field($_POST['search']) : '', + 's' => $strSearch, ]; $query_args = $this->applySorting($query_args, $sort_order); - $query_args['tax_query'] = $this->buildTaxQuery(); + $query_args['tax_query'] = $this->buildDynamicTaxQuery(); return $query_args; } @@ -498,7 +477,7 @@ class ContentFilterPlugin { * @since 1.4.0 */ private function buildDynamicTaxQuery() { - $taxonomies = get_option('content_filter_taxonomies', []); + $taxonomies = get_option('content_filter_taxonomies', []); // Get selected taxonomies from admin $tax_query = []; if (!empty($taxonomies)) { @@ -526,50 +505,6 @@ class ContentFilterPlugin { return []; } - /** Builds a taxonomy query array for filtering resources by type and subject. - * - * Constructs a taxonomy query based on the 'resource_type' and 'resource_subject' - * POST parameters. The function checks if these parameters are present and - * properly sanitizes them before adding them to the query. If both parameters - * are provided, the query will require both conditions to match using an 'AND' - * relation. - * - * @return array The constructed tax query array, or an empty array if no filters are applied. - */ - - private function buildTaxQuery() { - $tax_query = []; - - if (!empty($_POST['resource_type'])) { - $resType = is_array($_POST['resource_type']) ? array_map('sanitize_text_field', $_POST['resource_type']) : sanitize_text_field($_POST['resource_type']); - - $tax_query[] = [ - 'taxonomy' => 'resource_type', - 'field' => 'slug', - 'terms' => $resType, - 'operator' => 'IN' - ]; - } - - if (!empty($_POST['resource_subject'])) { - $tax_query[] = [ - 'taxonomy' => 'resource_subject', - 'field' => 'slug', - 'terms' => array_map('sanitize_text_field', $_POST['resource_subject']), - 'operator' => 'IN' - ]; - } - - if (!empty($tax_query)) { - return [ - 'relation' => 'AND', // Both filters must match - ...$tax_query - ]; - } - - return $tax_query; - } - /** Sends an AJAX response with resource filtering results. * * Constructs a response array containing the number of resources found, @@ -583,24 +518,31 @@ class ContentFilterPlugin { private function sendAjaxResponse($query) { $response = [ - 'count' => $query->found_posts, - 'filters' => [ - 'search' => isset($_POST['search']) ? sanitize_text_field($_POST['search']) : '', - 'resource_type' => !empty($_POST['resource_type']) ? sanitize_text_field($_POST['resource_type']) : '', - 'resource_subject' => !empty($_POST['resource_subject']) ? sanitize_text_field($_POST['resource_subject']) : '' + 'count' => $query->found_posts, + 'filters' => [ + 'search' => isset($_POST['search']) ? sanitize_text_field($_POST['search']) : '', ], - 'html' => ob_get_clean(), - 'pagination' => paginate_links([ - 'total' => $query->max_num_pages, - 'current' => isset($_POST['paged']) ? intval($_POST['paged']) : 1, - 'format' => '?paged=%#%', - 'add_args' => [], // Pass additional query arguments + 'html' => ob_get_clean(), + 'pagination' => paginate_links([ + 'total' => $query->max_num_pages, + 'current' => isset($_POST['paged']) ? intval($_POST['paged']) : 1, + 'format' => '?paged=%#%', + 'add_args' => [], // Pass additional query arguments 'prev_text' => '«', 'next_text' => '»', - 'type' => 'array', + 'type' => 'array', ]) ]; + // Include dynamic taxonomy filters in the response + $taxonomies = get_option('content_filter_taxonomies', []); + + foreach ($taxonomies as $taxonomy) { + if (!empty($_POST[$taxonomy])) { + $response['filters'][$taxonomy] = array_map('sanitize_text_field', (array) $_POST[$taxonomy]); + } + } + echo json_encode($response); wp_die(); } diff --git a/templates/filter-form.php b/templates/filter-form.php index 8c61b21..468c1ef 100644 --- a/templates/filter-form.php +++ b/templates/filter-form.php @@ -1,59 +1,36 @@ 'resource_type', 'hide_empty' => true]); -$resource_subjects = get_terms(['taxonomy' => 'resource_subject', 'hide_empty' => true]); +$selected_taxonomies = get_option('content_filter_taxonomies', []); // Get selected taxonomies ?>
- +
- - - + + +
- -
- - -
+ $taxonomy, 'hide_empty' => true]); + $taxonomy_obj = get_taxonomy($taxonomy); - -
- - -
- -
- - -
+ if (!empty($terms) && !empty($taxonomy_obj)): ?> +
+ + +
+ +
diff --git a/templates/filter-summary.php b/templates/filter-summary.php index ea49206..53b9863 100644 --- a/templates/filter-summary.php +++ b/templates/filter-summary.php @@ -16,37 +16,36 @@ if (!empty($_POST['search'])) { ]; } -// Handle the "Resource Type" filter -if (!empty($_POST['resource_type'])) { - $selected_types = is_array($_POST['resource_type']) ? $_POST['resource_type'] : [$_POST['resource_type']]; - $filters[] = [ - 'type' => 'resource_type', - 'value' => esc_html(implode(',', $selected_types)), - 'label' => 'Type: ' . esc_html(implode(', ', $selected_types)) - ]; -} +// Get selected taxonomies from admin settings +$selectedTaxonomies = get_option('content_filter_taxonomies', []); -// Handle the "Resource Subject" filter -if (!empty($_POST['resource_subject'])) { - $selected_subjects = is_array($_POST['resource_subject']) ? $_POST['resource_subject'] : [$_POST['resource_subject']]; - $filters[] = [ - 'type' => 'resource_subject', - 'value' => esc_html(implode(',', $selected_subjects)), - 'label' => 'Subject: ' . esc_html(implode(', ', $selected_subjects)) - ]; +// Handle dynamic taxonomy filters +foreach ($selectedTaxonomies as $taxonomy) { + if (!empty($_POST[$taxonomy])) { + $selectedTerms = is_array($_POST[$taxonomy]) ? $_POST[$taxonomy] : [$_POST[$taxonomy]]; + $taxonomyObj = get_taxonomy($taxonomy); + + if ($taxonomyObj) { + $filters[] = [ + 'type' => $taxonomy, + 'value' => esc_html(implode(',', $selectedTerms)), + 'label' => '' . esc_html($taxonomyObj->labels->singular_name) . ': ' . esc_html(implode(', ', $selectedTerms)) + ]; + } + } } // Display filters as HTML -$filter_html = ''; +$filterHtml = ''; if (!empty($filters)) { foreach ($filters as $filter) { - $filter_html .= '' + $filterHtml .= '' . $filter['label'] . ' ' . ' '; } } else { - $filter_html = 'None'; + $filterHtml = 'None'; } ?> @@ -57,19 +56,19 @@ if (!empty($filters)) {
- - + + + +

Filters applied:
- +

diff --git a/templates/resource-results.php b/templates/resource-results.php index df7bb96..b787d76 100644 --- a/templates/resource-results.php +++ b/templates/resource-results.php @@ -1,34 +1,38 @@ ID; $postTitle = get_the_title($postID); $postLink = get_permalink($postID); - $terms = get_the_terms($postID, 'resource_type'); + $postType = get_post_type($postID); + $terms = get_the_terms($postID, $taxonomy); + + $img = has_post_thumbnail($postID) ? get_the_post_thumbnail_url($postID, 'full') : get_field('admin', 'option')['imgDefault']['url'] ?? ''; ?>
- -
- - <?php echo esc_attr($postTitle); ?> - -
- +
+ + <?php echo esc_attr($postTitle); ?> + +
-

- name)) : ''; ?> +

+ Post Type:

-
+

-
- +
+
@@ -36,5 +40,5 @@ if (!empty($resources)) :
-

No resources found.

+

No results.

diff --git a/templates/style.css b/templates/style.css index 4e25046..66b5b3c 100644 --- a/templates/style.css +++ b/templates/style.css @@ -7,7 +7,7 @@ border: 1px solid #ccc; border-right: none; font-size: 1rem; - padding: .5rem; + padding: 1rem; width: 100%; } @@ -95,7 +95,7 @@ #resource-results { display: grid; - gap: 1rem; + gap: 1.5rem; grid-template-columns: repeat(1, minmax(0, 1fr)); } @@ -127,7 +127,7 @@ .pagination { display: flex; justify-content: center; - margin-top: 20px; + padding: 20px 0; } .pagination ul {