diff --git a/assets/script.js b/assets/script.js index cfb4f0f..6c975c3 100644 --- a/assets/script.js +++ b/assets/script.js @@ -1,4 +1,8 @@ jQuery(document).ready(function ($) { + /** Triggers filtering and pagination of resources based on the current form state. + * + * @param {number} [paged=1] - The page number to query. + */ function triggerFiltering(paged = 1) { let searchTerm = $('#search').val(); diff --git a/resource-filter.php b/resource-filter.php index dc916a5..c432b79 100644 --- a/resource-filter.php +++ b/resource-filter.php @@ -11,8 +11,7 @@ if (!defined('ABSPATH')) { exit; } // Prevent direct access require_once plugin_dir_path(__FILE__) . 'includes/template-loader.php'; class ResourceFilterPlugin { - /** - * Registers the necessary actions and filters. + /** Registers the necessary actions and filters. * * Adds a shortcode handler for the 'resource_filter' shortcode. * Enqueues the necessary scripts and styles. @@ -27,8 +26,7 @@ class ResourceFilterPlugin { add_action('wp_ajax_nopriv_filter_resources', [$this, 'filterResources']); } - /** - * Enqueues the necessary scripts and styles for the resource filter. + /** Enqueues the necessary scripts and styles for the resource filter. * * Checks if the 'resource_filter' shortcode is present on the page before loading. * Includes a CSS style and a JavaScript file specific to the plugin. @@ -49,8 +47,7 @@ class ResourceFilterPlugin { } } - /** - * Renders the resource filter form. + /** Renders the resource filter form. * * Loads the filter form template and displays a summary of the total resources. * Displays the number of resources and applied filters. @@ -67,6 +64,64 @@ class ResourceFilterPlugin { ob_start(); + $query = $this->getQuery(); + + $resTotal = $query->found_posts; // Default total resource count + + // Determine which form template to load + $attTmpl = ($atts['type'] === 'homepage') ? 'filter-homepage.php' : 'filter-form.php'; + $resForm = rfGetTemplate($attTmpl); + $summary = rfGetTemplate('filter-summary.php'); + + if ($resForm) { + include_once $resForm; + } else { + echo '
Error: Form template not found.
'; + } + + if ($atts['type'] === 'default') { + if ($summary) { + include_once $summary; + } else { + echo 'Error: Summary template not found.
'; + } + ?> + +Error: Form template not found.
'; - } - - if ($atts['type'] === 'default') { - if ($summary) { - include_once $summary; - } else { - echo 'Error: Summary template not found.
'; - } - ?> - -Error: Results template not found.
'; - } - - wp_reset_postdata(); - } - - /** - * AJAX handler for filtering resources. - * - * Searches for resources based on search term, resource type, and/or resource subject. - * Returns a JSON response with the count of resources found and the HTML for the resource results. - * - * Verifies the nonce and sanitizes the input data. - * - * @since 1.0.0 - */ - public function filterResources() { - $is_ajax = defined('DOING_AJAX') && DOING_AJAX; - - if ($is_ajax) { - check_ajax_referer('resource_filter_nonce', 'nonce'); - } - - $sort_order = isset($_POST['sort_order']) ? sanitize_text_field($_POST['sort_order']) : 'date_desc'; - - $query_args = [ - 'post_type' => 'resource', - 'posts_per_page' => 12, // Show 12 results per page - 'paged' => isset($_POST['paged']) ? intval($_POST['paged']) : 1, // Get current page number - 'tax_query' => [], - 's' => isset($_POST['search']) ? sanitize_text_field($_POST['search']) : '', - ]; - - // Sorting logic + private function applySorting($query_args, $sort_order) { switch ($sort_order) { case 'date_asc': $query_args['orderby'] = 'date'; @@ -273,34 +220,53 @@ class ResourceFilterPlugin { $query_args['order'] = 'DESC'; } - $tax_query = []; + return $query_args; + } - 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']); + /** Load and display resources. + * + * @return void + * + * @since 1.0.0 + */ + public function loadResources() { + $query_args = [ + 'post_type' => 'resource', + 'posts_per_page' => 12, // Show 12 results per page + 'paged' => max(1, get_query_var('paged', 1)), // Get current page number + ]; - $query_args['tax_query'][] = [ - 'taxonomy' => 'resource_type', - 'field' => 'slug', - 'terms' => $resType, - 'operator' => 'IN' - ]; + $query = new WP_Query($query_args); + $resources = $query->posts; + + $resResults = rfGetTemplate('resource-results.php'); + + if ($resResults) { + include_once $resResults; + } else { + echo 'Error: Results template not found.
'; } - 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' - ]; + wp_reset_postdata(); + } + + /** AJAX handler for filtering resources. + * + * Searches for resources based on search term, resource type, and/or resource subject. + * Returns a JSON response with the count of resources found and the HTML for the resource results. + * + * Verifies the nonce and sanitizes the input data. + * + * @since 1.0.0 + */ + public function filterResources() { + $is_ajax = defined('DOING_AJAX') && DOING_AJAX; + + if ($is_ajax) { + check_ajax_referer('resource_filter_nonce', 'nonce'); } - if (!empty($tax_query)) { - $query_args['tax_query'] = [ - 'relation' => 'AND', // Both filters must match - ...$tax_query - ]; - } + $query_args = $this->buildQueryArgs(); $query = new WP_Query($query_args); @@ -317,32 +283,116 @@ class ResourceFilterPlugin { } if ($is_ajax) { - // Prepare response JSON - $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']) : '' - ], - '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', - ]) - ]; - - echo json_encode($response); - wp_die(); + $this->sendAjaxResponse($query); } else { echo ob_get_clean(); } } + + /** Build the query arguments array for filtering resources. + * + * Uses the $_POST data to generate the query arguments for the WP_Query object. + * Sanitizes the input data to prevent SQL injection attacks. + * + * @return array The query arguments array. + * + * @since 1.0.0 + */ + private function buildQueryArgs() { + $sort_order = isset($_POST['sort_order']) ? sanitize_text_field($_POST['sort_order']) : 'date_desc'; + + $query_args = [ + 'post_type' => 'resource', + 'posts_per_page' => 12, // Show 12 results per page + 'paged' => isset($_POST['paged']) ? intval($_POST['paged']) : 1, // Get current page number + 'tax_query' => [], + 's' => isset($_POST['search']) ? sanitize_text_field($_POST['search']) : '', + ]; + + $query_args = $this->applySorting($query_args, $sort_order); + $query_args['tax_query'] = $this->buildTaxQuery(); + + return $query_args; + } + + /** 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, + * the applied filters, the HTML output of the resources, and pagination links. + * The response is then encoded as a JSON object and sent back to the client. + * + * @param WP_Query $query The query object containing the filtered resources. + * + * @since 1.0.0 + */ + + 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']) : '' + ], + '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', + ]) + ]; + + echo json_encode($response); + wp_die(); + } } new ResourceFilterPlugin();