label = __( 'Autocomplete', 'fwp' ); $this->fields = [ 'placeholder' ]; // ajax add_action( 'facetwp_autocomplete_load', [ $this, 'ajax_load' ] ); // css-based template add_action( 'facetwp_init', [ $this, 'maybe_buffer_output' ] ); add_action( 'facetwp_found_main_query', [ $this, 'template_handler' ] ); // result limit $this->limit = (int) apply_filters( 'facetwp_facet_autocomplete_limit', 10 ); } /** * For page templates with a custom WP_Query, we need to prevent the * page header from being output with the autocomplete JSON */ function maybe_buffer_output() { if ( isset( $_POST['action'] ) && 'facetwp_autocomplete_load' == $_POST['action'] ) { $this->is_buffering = true; ob_start(); } } /** * For CSS-based templates, the "facetwp_autocomplete_load" action isn't fired * so we need to manually check the action */ function template_handler() { if ( isset( $_POST['action'] ) && 'facetwp_autocomplete_load' == $_POST['action'] ) { if ( $this->is_buffering ) { while ( ob_get_level() ) { ob_end_clean(); } } $this->ajax_load(); } } /** * Generate the facet HTML */ function render( $params ) { $output = ''; $facet = $params['facet']; $value = (array) $params['selected_values']; $value = empty( $value ) ? '' : stripslashes( $value[0] ); $placeholder = empty( $facet['placeholder'] ) ? __( 'Start typing', 'fwp-front' ) : $facet['placeholder']; $placeholder = facetwp_i18n( $placeholder ); $output .= ''; $output .= ''; return $output; } /** * Filter the query based on selected values */ function filter_posts( $params ) { global $wpdb; $facet = $params['facet']; $selected_values = $params['selected_values']; $selected_values = is_array( $selected_values ) ? $selected_values[0] : $selected_values; $selected_values = stripslashes( $selected_values ); if ( empty( $selected_values ) ) { return 'continue'; } $sql = " SELECT DISTINCT post_id FROM {$wpdb->prefix}facetwp_index WHERE facet_name = %s AND facet_display_value LIKE %s"; $sql = $wpdb->prepare( $sql, $facet['name'], '%' . $selected_values . '%' ); return facetwp_sql( $sql, $facet ); } /** * Output any front-end scripts */ function front_scripts() { FWP()->display->json['no_results'] = __( 'No results', 'fwp-front' ); FWP()->display->assets['fComplete.js'] = FACETWP_URL . '/assets/vendor/fComplete/fComplete.js'; FWP()->display->assets['fComplete.css'] = FACETWP_URL . '/assets/vendor/fComplete/fComplete.css'; } /** * Load facet values via AJAX */ function ajax_load() { global $wpdb; // optimizations $_POST['data']['soft_refresh'] = 1; $_POST['data']['extras'] = []; $query = stripslashes( $_POST['query'] ); $query = FWP()->helper->sanitize( $wpdb->esc_like( $query ) ); $facet_name = FWP()->helper->sanitize( $_POST['facet_name'] ); $output = []; // simulate a refresh FWP()->facet->render( FWP()->request->process_post_data() ); // then grab the matching post IDs $where_clause = $this->get_where_clause( [ 'name' => $facet_name ] ); if ( ! empty( $query ) && ! empty( $facet_name ) ) { $sql = " SELECT DISTINCT facet_display_value FROM {$wpdb->prefix}facetwp_index WHERE facet_name = '$facet_name' AND facet_display_value LIKE '%$query%' $where_clause ORDER BY facet_display_value ASC LIMIT $this->limit"; $results = $wpdb->get_results( $sql ); foreach ( $results as $result ) { $output[] = [ 'value' => $result->facet_display_value, 'label' => $result->facet_display_value, ]; } } wp_send_json( $output ); } /** * (Front-end) Attach settings to the AJAX response */ function settings_js( $params ) { return [ 'loadingText' => __( 'Loading', 'fwp-front' ) . '...', 'minCharsText' => __( 'Enter {n} or more characters', 'fwp-front' ), 'noResultsText' => __( 'No results', 'fwp-front' ), 'maxResults' => $this->limit ]; } }